c++重拾 STL之heap(堆)使用

0、誤區!

1、堆排序排完後的堆和大頂堆、小頂堆不是一個概念!
2、堆分爲大頂堆和小頂堆,即要麼大頂堆(大根堆/最大堆),要麼小頂堆。
3、對於堆,堆的根節點一定是堆中所有節點的最大值或者最小值。
4、大頂堆只是說這個堆總每一個節點滿足:每一個節點大於或者等於其左右娃。並非這個堆一定是從大到小的序列。
5、所以才必須要有堆排序呀!堆排序排完了之後的,才一定是一個有序的序列。
6、堆實際上是用數組或者vector表現出來的一顆具有特殊結構的完全二叉樹。

1、heap

頭文件#include <algorithm>,STL在<algorithm.h>中實現了對存儲在數組或vector中的元素進行堆操作的函數,包括make_heap, pop_heap, push_heap, sort_heap。
【兩層:上層heap,底層vector(或數組)】,即用數組或vector數據容器來實現堆。
默認情況下是max-heap,該大頂堆實際上是以一個vector表現的完全二叉樹。

2、heap操作的四個函數:

  • make_heap( ):建立堆(要麼大頂堆,要麼小頂堆)
  • push_heap( ): 在堆中添加元素
  • pop_heap( ): 在堆中刪除元素
  • sort_heap( ): 堆排序
    相關參數:
    _First, _Last:可以隨機訪問的迭代器/ 指針
    _Comp: 比較函數(仿函數),其規則——如果函數的第一個參數小於第二個參數應返回true,否則返回false。

建立堆

make_heap(_First, _Last, _Comp)
默認是建立大最大堆的。對int類型,可以在第三個參數傳入greater<int>()得到最小堆。

在堆中添加元素

push_heap(_First, _Last)
要先在底層容器(數組或vector)里加入數據,再調用push_heap()。
實現細節:(1)添加元素到vector的尾部;(2)重新調整堆。
該算法必須是在滿足堆序的條件下,添加元素。
如,插入15到當前的大根堆裏,vector容器名字爲max_heap:

max_heap.push_back(15);
push_heap(max_heap.begin(), max_heap.end());

在堆中刪除元素

pop_heap(_First, _Last)
要先調用pop_heap(),再在容器(vector)中刪除元素
實現細節:(1)刪除堆頂元素;(2)用尾部元素替代max_heap[0];(3)重新調整堆。
(pop_heap操作實際上是我們把堆頂元素取出來,放到了數組或vector容器的末尾,用原來的末尾元素去替代,然後end迭代器減1,執行siftdown()下溯函數來重新調整堆)
注意算法執行完畢後,最大的元素並沒有被取走,而是放於底層容器的末尾。如果要取走,則可以使用底部容器(vector)提供的pop_back()函數。

pop_heap(max_heap.begin(), max_heap.end());//取出了堆頂元素(也叫刪除堆頂元素),放到了底層容器的末尾,原來末尾的元素替代堆頂,end迭代器減1,重新siftdown了堆
max_heap.pop_back();//徹底從底層容器(數組或vector)中刪除了元素

堆排序

sort_heap(_First, _Last)
既然每次pop_heap可以獲得堆頂的元素(假如是大頂堆,每次都獲得最大的元素,取出放到了底層容器的末尾),那麼我們持續對整個heap做pop_heap操作,每次講操作的範圍向前縮減一個元素(就是每次end迭代器減1)。最終我們可以獲得一個遞增的序列。
注意:這個排序是在一個堆上進行的。

關於堆排序,可以看看這個博客<<白話經典算法系列之七 堆排序>> https://blog.csdn.net/morewindows/article/details/6709644

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章