STL heap以vector为底层容器,从1开始存,2i为左子节点,即是个二叉堆,是个大根堆。
优先队列(priority queue)允许用户以任何次序将任何元素插入容器,但取出时要从优先权最大的元素开始取。二叉大根堆具有这样的特性,因此作为优先队列的底层机制。
能不能用list作为优先队列底层机制?
list作为优先队列底层机制可以实现元素插入的常数时间,但是要找到list的最值,却要对list做线性扫描。我们可以先对元素排序,这样,找到最值以及元素删除为常数时间,但是元素的插入又是线性时间。
能不能用二叉搜索树作为优先队列底层机制?
用二叉搜索树元素插入和最值取得都可以在O(logn)内完成,但是这样小题大做:第一,二叉搜索树的输入需要足够的随机性;第二,二叉搜索树的实现不容易。
push_heap(first,last):(当数组中已经放入了一个新的元素并且这个元素位于容器最尾端,数组之前是有序的)用来将尾端元素调整至有序的位置
pop_heap(first,last):将最大元素放置最尾端,然后调整数组使有序(最大元素要调用pop_back()进行删除,现在还未删,数组之前是有序的)
sort_heap(first,last):对所有元素进行整体升序排列(数组之前是满足二叉堆的规则的,所以实际实现是用pop_heap每次排列后最大元素归位)
make_heap(first,last):对无序的元素进行排序使得它满足二叉堆的规则
push_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以及make_heap的核心算法是一样的,如下:
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; // 弹出元素的有子孩 // 调整heap元素位置 while (secondChild < len) { // 选择两个子孩中较大的进行操作, 使用secondChild表示其偏移 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); }