STL源码剖析——heap

本文探讨STL中的Heap操作,虽然没有Heap容器,但提供了相关算法。Heap常用于priority queue,通常使用vector作为容器。插入元素时采用"向上维护",而取出元素则采用"向下维护"。push_heap、pop_heap和sort_heap是关键操作,文中通过源码分析解释了这些操作的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Heap堆是常用的数据结构,Heap中也可以存放元素。但是STL中并没有提供Heap容器,只是提供了关于Heap操作的算法。只要支持RandomAccessIterator的容器都可以作为Heap容器。


Heap分为max heap和min heap,max heap中每次取出的结点时heap结构中值最大的结点,min heap中每次取出的结点时heap结构中值最小的结点。


Heap不允许遍历其结点,所以Heap没有迭代器。


在实际应用中,经常用vector作为heap容器,heap经常作为priority queue。


当向heap中插入元素时,插入到末尾,“向上维护”即可:指的是把插入结点与其父结点比较,如果不符合堆得要求则交换,再向上维护其父结点……

下图是push_heap的示意图。

 

从图中可以看到算法的过程是将新加入堆的值(50),层层上挪,直到正确的位置。下面来看,摘录出来的代码。

template <class RandomAccessIterator>
inline void push_heap(RandomAccessIterator first, RandomAccessIterator last) {
	// 注意,调用该函数时候,新元素位于最后一个位置(last-1)。
	__push_heap_aux(first, last, distance_type(first), value_type(first));
}

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)));
	// (last-first)–1代表新元素的索引,0是堆首的索引,*(last - 1)是新加入的值
}

template <class RandomAccessIterator, class Distance, class T>
void __push_heap(RandomAccessIterator first, Distance holeIndex,
	Distance topIndex, T value) {
	Distance parent = (holeIndex - 1) / 2;	// 找出父節點
	while (holeIndex > topIndex && *(first + parent) < value) {
		// 尚未到达顶端,且父节点小于新值
		// 由于以上使用 operator<,可知 STL heap 是max-heap
		*(first + holeIndex) = *(first + parent);	// 令洞值为父值
		holeIndex = parent; // percolate up:调整洞号,向上提升至父节点。
		parent = (holeIndex - 1) / 2;	// 新洞的父节点
	}    // 持续至顶端,或满足 heap 的次序特性为止。
	*(first + holeIndex) = value;	// 令洞值为新值。
}

push_heap的用法是输入迭代器对,并且保证[first,last-1)是最大堆,*(last-1)是新加入的元素。push_heap调用辅助函数__push_heap_aux。至于为什么需要这个辅助函数了?应该是为了提取出distance_type和value_type吧,这两个内联函数的定义,可以参考stl源码剖析迭代器的那章。下面来思考真正的实现函数__push_heap。这个函数需要新加入元素位置holeIndex和堆首位置topIndex,另外还有保存好的新加入值。算法的过程很简单,就是上溯holeIndex,找到真正满足条件的位置(无法继续上回溯),然后把value放入该位置即可。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值