关于堆(heap)

本文介绍了堆的概念,特别是完全二叉树的定义,并详细阐述了堆的性质,包括左、右子节点的编号规则和高度计算。此外,讨论了堆的基本操作,如上浮、下沉、插入和删除,并提供了小根堆的模板。还推荐了几道入门级的在线编程题目以巩固理解。

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

说在前面

我第一次接触堆这个东西是在做堆排序的时候。这玩意还不错,难度也不大,可以用的地方很多,值得玩一玩。

前置知识:

完全二叉树

完全二叉树 ,顾名思义是一种二叉树就是说 (假设树根深度为1 )深度为k的二叉树 ,第1至第k-1层的结
点都是满的,也就是说 ,如果一颗二叉树满足第i(1<=i<=K-1)层的结点数为2 * i-1  ,0<第K层的结点数
<=2 * k-1  ,并且最下面一层的结点都集中在该层最左边的若干位置 ,那么它就是一颗完全二叉树。

like this:

堆的性质及其基本操作:

堆的性质

1.编号为i的结点的左二子的编号为2 * i  ,右儿子编号为2 * i + 1  ,父结点编号为i / 2 (假设有)

2.n个结点的堆的高度为log2(n + 1)的对数

3.h[i] <= h[2 * i], h[i] <= h[2 * i + 1] (或者 h[i] >= h[2 * i], h[i] >= h[2 * i + 1] )ps:前面那个是小
根堆 ,即h[1]是最小值 ;而后者为大根堆 ,即h[1]是最大值。

 

基本操作

1.上浮(up)

void up(int x) { //h[x]上浮
	while(x > 1 && h[x] < h[x >> 1]) {
		swap(h[x], h[x >> 1]);
		x >>= 1;
	}
}

 

2.下沉(down)

void down(int x) { //h[x]下沉,len是堆中元素个数
	int y = x << 1;
	while(y <= len) {
		if(y + 1 <= len && h[y + 1] < h[y]) y++;
		if(h[y] < h[x]) {
			swap(h[x], h[y]);
			x = y;
			y = x << 1;
		} else break;
	}
}

3.读入(insert)

void insert(int x) {
	h[++len] = x;
	up(len);
}

4.删除(delete)

void del(int x) {  //删除元素h[x]
	h[x] = h[len--];
	up(x);
	down(x);
}

下面放一个模板(小根堆):

#include<bits/stdc++.h>
using namespace std;
int n, k;
int a[100010], h[100010];
int b[100010];
int cnt, len;

void up(int x) {
	while (x > 1 && h[x] < h[x >> 1]) {
		swap(h[x], h[x >> 1]);
		x >>= 1;
	}
}

void down(int x) {
	int y = x << 1;
	while (y <= len) {
		if (y + 1 <= len && h[y + 1] < h[y]) y++;
		if (h[y] < h[x]) {
			swap(h[x], h[y]);
			x = y;
			y = x << 1;
		}
		else break;
	}
}

void insert(int x) {
	h[++len] = x;
	up(len);
}

int solve() {
	int d = h[1];
	h[1] = h[len--];
	down(1);
	return d;
}

int main() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
		insert(a[i]);
	}
	for (int i = 1; i <= n; i++) {
		cout << solve() << " ";
	}
}
/*
13
19 17 16 12 9 15 1 2 11 7 3 10 14
*/

几个题目:

入门OJ1551 合并果子

入门OJ1552 合并果子2

入门OJ2104 ksum

### 最小(Min-Heap)概念 最小是一种特殊的完全二叉树结构,其特点是父节点的值总是小于或等于子节点的值。这种特性使得顶始终存储着整个集合中的最小值[^1]。 在实际应用中,最小常用于实现优先队列、调度算法以及各种优化问题。由于插入和删除操作的时间复杂度均为 \(O(\log n)\),因此它非常适合处理动态数据集。 --- ### Python 实现 Min-Heap 以下是基于 Python 的 `min_heap` 最小实现: ```python class MinHeap: def __init__(self): self.heap = [] def insert(self, value): """向中插入新元素""" self.heap.append(value) self._sift_up(len(self.heap) - 1) def extract_min(self): """提取并返回中的最小值""" if not self.heap: return None if len(self.heap) == 1: return self.heap.pop() root_value = self.heap[0] self.heap[0] = self.heap[-1] del self.heap[-1] self._sift_down(0) return root_value def _parent_index(self, index): """获取父节点索引""" return (index - 1) // 2 def _left_child_index(self, index): """获取左子节点索引""" return 2 * index + 1 def _right_child_index(self, index): """获取右子节点索引""" return 2 * index + 2 def _sift_up(self, index): """上浮调整""" parent_idx = self._parent_index(index) while index > 0 and self.heap[parent_idx] > self.heap[index]: self.heap[parent_idx], self.heap[index] = self.heap[index], self.heap[parent_idx] index = parent_idx parent_idx = self._parent_index(index) def _sift_down(self, index): """下沉调整""" size = len(self.heap) while True: smallest = index left_child = self._left_child_index(index) right_child = self._right_child_index(index) if left_child < size and self.heap[left_child] < self.heap[smallest]: smallest = left_child if right_child < size and self.heap[right_child] < self.heap[smallest]: smallest = right_child if smallest != index: self.heap[smallest], self.heap[index] = self.heap[index], self.heap[smallest] index = smallest else: break # 测试代码 if __name__ == "__main__": min_heap = MinHeap() elements = [3, 1, 6, 5, 2, 4] for elem in elements: min_heap.insert(elem) result = [] while True: val = min_heap.extract_min() if val is None: break result.append(val) print(result) # 输出应为升序序列 [1, 2, 3, 4, 5, 6] ``` 上述代码实现了基本的最小功能,包括插入 (`insert`) 和提取最小值 (`extract_min`) 操作,并通过 `_sift_up` 和 `_sift_down` 方法维护性质。 --- ### 应用场景 #### 1. **优先队列** 使用最小可以效地管理一组具有不同优先级的任务。每次从队列中取出的是优先级最的任务(即数值最小的任务),从而满足实时系统的调度需求。 #### 2. **K 小/大元素查找** 利用最小可以在大规模数据集中快速找到前 K 大或前 K 小的元素。例如,在海量日志分析中筛选出访问量最大的页面[^3]。 #### 3. **Dijkstra 算法加速** Dijkstra 是一种经典的最短路径算法,而使用最小作为辅助数据结构可显著降低更新距离的操作成本,使整体性能提升至 \(O((V+E)\log V)\)[^4]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值