標籤:style blog http color 使用 os
本文為senlie原創,轉載請保留此地址:http://blog.csdn.net/zhengsenlie
heap
-------------------------------------------------------------------------
binary heap 是一種完全二叉樹。
隱式標記法:以 array 表述 tree。
小技巧:將 array 的 #0 元素保留,則第 i 個元素的左右子節點分別是 2i 和 2i + 1,
父節點是i/2 --> STL 裡沒有採用這種小技巧
將 array 無法動態改變大小,所以用 vector 替代 array
這個檔案裡提供了各種堆操作的演算法,注意沒有 heap 類
圖 4-20
樣本:
#include <vector>#include <iostream>#include <iterator>#include <algorithm>using namespace std;void display(const vector<int> &v){copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));cout << endl;}int main(){int ia[] = {0,1,2,3,4,8,9,3,5};vector<int> ivec(ia, ia + sizeof(ia)/sizeof(int));make_heap(ivec.begin(),ivec.end());display(ivec);ivec.push_back(7);push_heap(ivec.begin(), ivec.end());display(ivec);pop_heap(ivec.begin(), ivec.end());ivec.pop_back();display(ivec);sort_heap(ivec.begin(), ivec.end());display(ivec);}
源碼:
#ifndef __SGI_STL_INTERNAL_HEAP_H#define __SGI_STL_INTERNAL_HEAP_H__STL_BEGIN_NAMESPACE#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)#pragma set woff 1209#endiftemplate <class RandomAccessIterator, class Distance, class T>void __push_heap(RandomAccessIterator first, Distance holeIndex, Distance topIndex, T value) { Distance parent = (holeIndex - 1) / 2; //找到父節點 // 當尚未到達頂端,且父節點小於新值(於是不符合 heap 的次序特性) while (holeIndex > topIndex && *(first + parent) < value) { *(first + holeIndex) = *(first + parent); //令洞值為父值 holeIndex = parent; //調整洞號,向上提升至父節點 parent = (holeIndex - 1) / 2; //新洞的父節點 } *(first + holeIndex) = value; //令洞值為新值,完成插入操作}template <class RandomAccessIterator, class Distance, class T>inline void __push_heap_aux(RandomAccessIterator first, RandomAccessIterator last, Distance*, T*) { __push_heap(first, Distance((last - first) - 1), Distance(0), T(*(last - 1)));}/*調用此函數時,新元素應已置於底部容器的最尾端 --> 什麼時候置的? --> stl_heap 不對外開放,只在 STL 內部使用,使用 push_heap 的其他 STL 程式應該注意在調用push_heap 函數前,將新元素置於 heap 底部容器的最尾端*/template <class RandomAccessIterator>inline void push_heap(RandomAccessIterator first, RandomAccessIterator last) { __push_heap_aux(first, last, distance_type(first), value_type(first));}template <class RandomAccessIterator, class Distance, class T, class Compare>void __push_heap(RandomAccessIterator first, Distance holeIndex, Distance topIndex, T value, Compare comp) { Distance parent = (holeIndex - 1) / 2; while (holeIndex > topIndex && comp(*(first + parent), value)) { *(first + holeIndex) = *(first + parent); holeIndex = parent; parent = (holeIndex - 1) / 2; } *(first + holeIndex) = value;}//STL 裡很多這種函數體裡直接調用另一個函數的函數,感覺這樣不太好,增加了堆棧的開銷,//為什麼不直接就調用裡面那個函數呢template <class RandomAccessIterator, class Compare, class Distance, class T>inline void __push_heap_aux(RandomAccessIterator first, RandomAccessIterator last, Compare comp, Distance*, T*) { __push_heap(first, Distance((last - first) - 1), Distance(0), T(*(last - 1)), comp);}template <class RandomAccessIterator, class Compare>inline void push_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp) { __push_heap_aux(first, last, comp, distance_type(first), value_type(first));}template <class RandomAccessIterator, class Distance, class T>void __adjust_heap(RandomAccessIterator first, Distance holeIndex, Distance len, T value) { Distance topIndex = holeIndex; Distance secondChild = 2 * holeIndex + 2; while (secondChild < len) { if (*(first + secondChild) < *(first + (secondChild - 1))) secondChild--; *(first + holeIndex) = *(first + secondChild); holeIndex = secondChild; secondChild = 2 * (secondChild + 1); } if (secondChild == len) { *(first + holeIndex) = *(first + (secondChild - 1)); holeIndex = secondChild - 1; } __push_heap(first, holeIndex, topIndex, value);}template <class RandomAccessIterator, class T, class Distance>inline void __pop_heap(RandomAccessIterator first, RandomAccessIterator last, RandomAccessIterator result, T value, Distance*) { *result = *first; __adjust_heap(first, Distance(0), Distance(last - first), value);}template <class RandomAccessIterator, class T>inline void __pop_heap_aux(RandomAccessIterator first, RandomAccessIterator last, T*) { //pop 操作的結果應該底部容器的第一個元素 __pop_heap(first, last - 1, last - 1, T(*(last - 1)), distance_type(first));}template <class RandomAccessIterator>inline void pop_heap(RandomAccessIterator first, RandomAccessIterator last) { __pop_heap_aux(first, last, value_type(first));}template <class RandomAccessIterator, class Distance, class T, class Compare>void __adjust_heap(RandomAccessIterator first, Distance holeIndex, Distance len, T value, Compare comp) { Distance topIndex = holeIndex; Distance secondChild = 2 * holeIndex + 2; //洞節點的右子節點 while (secondChild < len) { //當還有左、右子節點的時候 if (comp(*(first + secondChild), *(first + (secondChild - 1)))) secondChild--; *(first + holeIndex) = *(first + secondChild); //令較大值為洞值 holeIndex = secondChild; //令洞號下移至較大子節點處 secondChild = 2 * (secondChild + 1); //找出新洞節點的子節點 } if (secondChild == len) { //當只有左節點的時候 *(first + holeIndex) = *(first + (secondChild - 1)); holeIndex = secondChild - 1; } __push_heap(first, holeIndex, topIndex, value, comp);}template <class RandomAccessIterator, class T, class Compare, class Distance>inline void __pop_heap(RandomAccessIterator first, RandomAccessIterator last, RandomAccessIterator result, T value, Compare comp, Distance*) { //將首值(即要 pop 出來的值)存放在 result 所指處。 *result = *first; //重新調整 heap , 洞號為0,欲調整值為 value __adjust_heap(first, Distance(0), Distance(last - first), value, comp);}template <class RandomAccessIterator, class T, class Compare>inline void __pop_heap_aux(RandomAccessIterator first, RandomAccessIterator last, T*, Compare comp) { __pop_heap(first, last - 1, last - 1, T(*(last - 1)), comp, distance_type(first));}template <class RandomAccessIterator, class Compare>inline void pop_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp) { __pop_heap_aux(first, last, value_type(first), comp);}template <class RandomAccessIterator, class T, class Distance>void __make_heap(RandomAccessIterator first, RandomAccessIterator last, T*, Distance*) { if (last - first < 2) return; Distance len = last - first; Distance parent = (len - 2)/2; while (true) { __adjust_heap(first, parent, len, T(*(first + parent))); if (parent == 0) return; parent--; }}template <class RandomAccessIterator>inline void make_heap(RandomAccessIterator first, RandomAccessIterator last) { __make_heap(first, last, value_type(first), distance_type(first));}template <class RandomAccessIterator, class Compare, class T, class Distance>void __make_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp, T*, Distance*) { if (last - first < 2) return; Distance len = last - first; //找出第一個需要重排的子樹的頭部,以 parent 標示出。 Distance parent = (len - 2)/2; while (true) { __adjust_heap(first, parent, len, T(*(first + parent)), comp); if (parent == 0) return; //走完根節點,就結束了。 parent--; //實際上就是沿著第一個父節點從左至右調整值使父節點的值大於(或小於)兩個子節點 }}template <class RandomAccessIterator, class Compare>inline void make_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp) { __make_heap(first, last, comp, value_type(first), distance_type(first));}template <class RandomAccessIterator>void sort_heap(RandomAccessIterator first, RandomAccessIterator last) { //每次執行一次 pop_heap() ,極值被放在尾端 //扣除尾端再執行一次 pop_heap(),次極值又被放在新尾端 //一直這樣下去,最後即可得到排序結果 while (last - first > 1) pop_heap(first, last--);}template <class RandomAccessIterator, class Compare>void sort_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp) { while (last - first > 1) pop_heap(first, last--, comp);}#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)#pragma reset woff 1209#endif__STL_END_NAMESPACE#endif /* __SGI_STL_INTERNAL_HEAP_H */// Local Variables:// mode:C++// End: