一:堆相關的概念:
1>什麼是堆 :堆數據結構是一種數組對象,它可以被視爲一棵完全二叉樹結構。
2>堆的分類 :最大堆:每個父節點的都大於孩子節點。最小堆:每個父節點的都小於孩子節點。例如下面的兩個堆:
二:堆的向下調整過程 (拿大堆舉例)
首先給定父親節點的下標,由於堆存放在數組中,下標一定連續,所以可以看作一棵完全二叉樹,我們只需要求出該父親節點對應左孩子的下標,使得child值爲孩子中較大的一個的下標,若孩子中大的節點的值比父節點的值還大,則進行交換,再向下循環操作。反則不進行操作。可參考下面對應代碼梳理一遍。
實現代碼如下:
void _AdjustDown(int root)
{
int parent = root;
int child = parent * 2 + 1 ;
while (child < _a.size ())
{
if (child + 1 < _a.size () && _a[child + 1 ] > _a[child])
child++;
if (_a[child] > _a[parent ])
{
swap(_a[child], _a[parent ]);
parent = child;
child = parent * 2 + 1 ;
}
else
break ;
}
}
二:堆的上調過程
上調過程多出現於在堆的push操作,當整個堆最後插入一個值後,隻影響該節點到根路徑上的節點,因爲在沒插入之前該堆是符合規則的。
簡單實現代碼如下:
void _AdjustUp(int child)
{
int parent = (child - 1 ) >> 1 ;
while (child > 0 )
{
if (_a[child] > _a[parent ])
{
swap(_a[child], _a[parent ]);
child = parent ;
parent = (child - 1 ) >> 1 ;
}
else
{
break ;
}
}
}
三:堆的push操作
由於堆底層是一個數組,我們可以使用vector來實現,當進行push操作時,首先需要將該節點插入到數組的尾部,其次以該節點下標爲child,進行上調操作,具體圖示可參考二。
void Push (const T& x )
{
_a.push _back(x )
_AdjustUp(_a.size () - 1 )
}
四:堆的pop操作
對於一個堆,我們想要刪除頭節點時,可以採用替代刪除法。先將頭與數組最後一個值進行交換,再對頭節點進行向下調整操作。
void Pop()
{
assert(!_a.empty() ) ;
swap(_a[0 ], _a[_a.size() - 1 ]) ;
_a.pop_back ();
_AdjustDown(0 ) ;
}
五:建堆操作
當我們給定一個數組,想要將其放到一個大堆或者小堆時,首先要做的是將給定數組的值全部壓入堆中,接下來就是找到最後一個節點的父親,再依次進行向下調整操作,直到調整到頭節點,完成整個建堆操作。
Heap(const T* arr, int n)
{
_a.reserve(n);
for (int i = 0 ; i < n; i++)
_a.push_back(arr[i]);
for (int i = (_a.size() - 2 ) >> 1 ; i >= 0 ; --i)
_AdjustDown(i);
}