Heap堆是常用的数据结构,Heap中也可以存放元素。但是STL中并没有提供Heap容器,只是提供了关于Heap操作的算法。只要支持RandomAccessIterator的容器都可以作为Heap容器。Heap的背景是建立在优先队列的基础上,priority queue允许我们任意的插入一个元素,但是会自动将元素进行排序,使得取出时一定是从优先级最高的元素开始取。我们可以考虑使用list这种数据结构完成priority queue,也就是说,我们可以轻松的完成插入(因为list其实是线性链表),但是我们要取得list中的极值时,则需要对整个list进行遍历。或者我们可以这样考虑,将元素插到list的合适位置,这样一来,虽然很容易取得极值,但是我们的搜索插入也是需要线性搜索。
template<calss RandomAccessIterator> inline void upSortLastElem( RandomAccessIterator first, RandomAccessIterator last) { __push_heap_aux(first,last,distance_type(first),value_type(first)); } //向上维护 template <class RandomAccessIterator, class Distance, class T> void __push_heap(RandomAccessIterator first, Distance holeIndex, Distance topIndex, T value) { Distance parent = (holeIndex - 1) / 2; // 找出父结点 //父结点不是heap顶 且 父节点的值小于孩子结点(小于号<可以看出STL维护的是max heap) while (holeIndex > topIndex && *(first + parent) < value) { *(first + holeIndex) = *(first + parent); // 父结点下调 holeIndex = parent; // 维护父结点 parent = (holeIndex - 1) / 2; } //已达到heap顶或者满足heap性质后,给新插入元素找到合适位置 *(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))); } //往heap添加元素。注意:此函数调用时,元素已经添加到末尾了,且迭代器已经加1了 template <class RandomAccessIterator> inline void push_heap(RandomAccessIterator first, RandomAccessIterator last) { // 注意,此函式被呼叫時,新元素應已置於底層容器的最尾端。 __push_heap_aux(first, last, distance_type(first), value_type(first)); } //向上维护,允许用自己定义的comp函数,这是未必是max heap了 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; }
pop_heap算法 执行下溯程序,
template <class RandomAccessIterator, class T> inline void __pop_heap_aux(RandomAccessIterator first, RandomAccessIterator last, T*) { __pop_heap(first, last-1, last-1, T(*(last-1)), distance_type(first)); /* 根据implicit representation heap的次序性,pop后的结果是容器的第一个元素。 把最后一个元素放到到容器头,因此维护时维护区间是[first last-1)。 */ } //取出heap顶元素,按照max heap属性来维护heap template <class RandomAccessIterator> inline void pop_heap(RandomAccessIterator first, RandomAccessIterator last) { __pop_heap_aux(first, last, value_type(first)); } //向下维护heap,允许执行比较函数comp 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); }
sort_heap 算法
template< class RandomAccessIterator> void sort_heap(RandomAccessIterator first, RandomAccessIterator last) { <span style="white-space:pre"> </span>while ( last-first>1) //while 判断的边界 <span style="white-space:pre"> </span>//堆排序只需要不断的进行pop,就可以得到有序堆 <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span>Pop_heap(first, last--); //不断调用pop_heap来达到效果,因为pop过程中并不是把元素删了,而是把最大的移到最后 <span style="white-space:pre"> </span>last--; <span style="white-space:pre"> </span>} }
make_heap算法
template<class RandomAccessIterator> inline void make_heap( RandomAccessIterator first , RandomAccessIterator last) { <span style="white-space:pre"> </span>__make_heap( first, last,value_type(first), distance_type(first)); } template<class RandomAccessIterator,class T, class Distance> void __make_heap(RandomAccessIterator first, RandomAccessIterator last, T*,Distance*) { <span style="white-space:pre"> </span>if (last – first <2 ) return; <span style="white-space:pre"> </span>Distance len = last – first; <span style="white-space:pre"> </span>Distance parent = (len-2)/2; //只能对树的内部节点进行“下溯” <span style="white-space:pre"> </span>while(true) <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span> __adjust_heap( first, parent, len,T(*(first+parent))); <span style="white-space:pre"> </span> If(parent==0) return; <span style="white-space:pre"> </span> --parent; <span style="white-space:pre"> </span>} }