開發過程,經常需要對資料集合進行維護。
維護資料結合的資料結構可統稱為容器。
最小堆是維護資料集合的容器的一種,
最小堆具備如下性質:
設v[i]為位置i的元素值
1. 對維護的n個元素,順序儲存於索引為1-n的陣列位置
2. 對索引i,
若索引2*i <= n,有v[i] <= v[2*i],
若索引2*i+1 <= n,有v[i] <= v[2*i+1]。
最小堆為具備特殊性質的容器。
template class minheap
;
minheap()template minheap::minheap()
minheap(const array::dynarray& arrelements_)template minheap::minheap(const array::dynarray& arrelements_)
template void minheap::buildheap(const array::dynarray& arrelements_)
for (int _i = _nsize; _i >= 1; _i--) }
template void minheap::adjust(int nindex_)
if (_nr < m_arrelements.getsize()
&& m_arrelements[_nr] < _nmin)
if (_nminpos == nindex_)
else
}
template minheap::minheap(const minheap& mha_)
template typename minheapminheap::operator=(const minheap& mha_)
m_arrelements = mha_.m_arrelements;
return *this;
}
template minheap::~minheap()
template void minheap::add(const t& nt_)
if (_nsize == 0)
// 新元素索引
if ((_nsize + 1) % 2 == 0)
else
// 將新增位置元素設定為指定值
if (nt_ < m_arrelements[_nsize + 1])
else if (nt_ > m_arrelements[_nsize + 1])
else }
template void minheap::smaller(int npos_)
int _np = npos_ / 2;
if (m_arrelements[_np] <= m_arrelements[npos_])
else }
template void minheap::bigger(int npos_)
if (_nr < m_arrelements.getsize()
&& m_arrelements[_nr] < _nmin)
if (_nminpos == npos_)
else
}
template void minheap::delete(int nindex_)
if (_nsize == 1)
m_arrelements[nindex_] = m_arrelements[1] - 1;// 變得比最小還小
smaller(nindex_);// 調節後,原nindex位置元素必位於索引為1位置
m_arrelements[1] = m_arrelements[_nsize];
m_arrelements.deletebyindex(_nsize);
bigger(1);
}
template int minheap::find(std::functionfun_)
} return -1;
}
輸入:無序的含n個元素的陣列
演算法目標:
輸入陣列中n個元素以符合最小堆定義的方式儲存於m_arrelements的索引1,...,n處
正確性證明:
演算法主體採用迴圈迭代實現,迭代實現的一般用迴圈不變式證明正確性
for (int _i = _nsize; _i >= 1; _i--)
迴圈不變式:
區間[_i+1, _nsize]內各個元素均滿足,
對區間內任意位置k的元素,有以下位置約束
若2*k位置元素存在,則有v[k] <= v[2*k]
若2*k+1位置元素存在,則有v[k] <= v[2*k+1]
證明:初始時,區間為[_nsize+1, _nsize]為空 區間,迴圈不變式成立
對_i = k的迭代
依據迴圈不變式【本次迴圈迭代前的各個迭代後,迴圈不變式均滿足】
所有_i > k的迭代處理後,迴圈不變式均滿足
只需證明:adjust(nindex_)
在[nindex_+1, nsize]區間內任意元素均滿足 位置約束前提下,
通過調節[nindex_, nsize]區間內元素位置,
可實現[nindex_, nsize]區間內任意元素均滿足 位置約束的效果即可。
如上述證明成立,則,迴圈不變式成立。
證明:adjust(nindex_)具備上述性質
1. 若k位置元素小於其可能存在的左孩子,右孩子元素
無需處理。
此時,結合演算法前提,可知結論成立。
2. 若k位置元素 比起左孩子,或右孩子大
讓孩子中最小的元素 和 k位置元素交換位置
交換後,對k位置,滿足位置約束
對換入k位置元素的位置t, 該位置的元素相比原來變大了
此時我們希望求解
在[t+1, nsize]區間內任意元素均滿足 位置約束前提下,
通過調節[t, nsize]區間內元素位置,
可實現[t, nsize]區間內任意元素均滿足 位置約束的效果即可。
這和要求解元素問題屬於同類問題。
綜合,在adjust處理中,
我們要麼立即求解。要麼轉化為對同類問題的求解。
我們可以證明,演算法在轉化為同類求解的時候,總是朝著更易終止的方向進行,且可以證明,至多在經歷θ(lg(n))次,遞迴後,必然可以得到立即求解的情形。
綜合,演算法成立。
按新增元素相比預先填充元素大小,實際演變為證明
smaller,bigger
演算法前提/背景:
本來區間[1, nsize]內所有位置均滿足位置約束
現在npos位置元素變小了,導致此位置可能不滿足位置約束
演算法目標:
通過對[1, nsize]各個元素進行位置調整,
使區間[1, nsize]內所有位置均滿足位置約束
1. 若npos_ == 1,無需處理
2. 若 m_arrelements[_np] <= m_arrelements[npos_],無需處理
3. m_arrelements[_np] > m_arrelements[npos_],
交換_np和npos_位置內容。
此時要求解問題:
本來區間[1, nsize]內所有位置均滿足位置約束
現在_np位置元素變小了,導致此位置可能不滿足位置約束
希望通過對[1, nsize]各個元素進行位置調整,使區間[1, nsize]內所有位置均滿足位置約束
這是和原問題同型別的問題
綜合,在smaller處理中,我們要麼立即求解。要麼轉化為對同類問題的求解。
我們可以證明,演算法在轉化為同類求解的時候,總是朝著更易終止的方向進行,且可以證明,至多在經歷θ(lg(n))次,遞迴後,必然可以得到立即求解的情形。
minheap::bigger類似minheap::smaller
假設元素集合中元素個數為n
minheap()時間複雜度θ(1)
minheap(const array::dynarray& arrelements_)時間複雜度θ(nlg(n))
時間複雜度θ(n)
時間複雜度θ(n)
時間複雜度θ(1)
時間複雜度o(lg(n))
時間複雜度o(lg(n))
時間複雜度o(n)
基本資料結構 最小堆
最小堆,是完全二叉樹,其基本定義是任何乙個節點小於其左右子樹的節點 常見操作 加入乙個值,取最小值,刪除最小值 加入乙個值,直接加入到末尾a size 然後該元素上浮到合適位置 最大值即根節點 a 0 刪除最小值,讓末尾元素填充到a 0 然後該元素下沉到合適位置 下沉過程中,選取左右子節點的最小值,...
資料結構 大小堆
如果有乙個關鍵碼的集合k 把它的所有元素按完全二叉樹 的順序儲存方式儲存在乙個一維陣列中,並滿足 ki k2 i 1 且 ki k2 i 2 ki k2 i 1 且 ki k2 i 2 i 0,1,2 則稱這個堆為最小堆 或最大堆 最大堆和最小堆是二叉堆的兩種形式。最大堆 根結點的鍵值是所有堆結點鍵...
資料結構 最小堆的類模板實現
堆資料結構是一種陣列物件,它可以被視為一科完全二叉樹結構。它的特點是父節點的值大於 小於 兩個子節點的值 分別稱為最大堆和最小堆 它常用於管理演算法執行過程中的資訊,應用場景包括堆排序,優先佇列等。1 根結點若有子樹,則子樹一定也是堆。2 根結點一定大於 或小於 子結點。因為要求堆必須是完全二叉樹,...