acwing基础课ch2-堆
            
               约 822 字 
                 预计阅读 2 分钟 
         堆/优先队列
堆是什么
- 堆是一颗完全二叉树。
 
- 大顶堆:父亲结点的值大于左右子树的结点。
 
- 小顶堆:父亲结点的值小于左右子树的结点。
 
堆的操作与优点
优点
- O(1)时间内找出最大或最小的数
 
- 添加或者删除一个数需要O(logn)的时间复杂度
 
支持操作-最小堆
- 向上调整:把欲调整节点与其父亲节点比较,直到其小于父亲节点。
 
- 向下调整:将当前结点与左右孩子比较,直到其比左右儿子都小。
 
存储方式
- 使用一维数组进行存储,1号点为根节点,同时使用一个变量记录节点的总数。
 
- 使用数组静态表示堆$heap[i]$从1开始,该节点左孩子为$heap[2i]$,该节点右孩子为$heap[2i+1]$。
 
- 因为堆为完全二叉树,所以数组肯定可以放满。
 

建立堆
- 先将堆初始化(数组初始化)。
 
- 从n/2到1向下调整每一个数。
 
- 时间复杂度$O(n)$,而通过插入每一个元素建立堆的时间复杂度是$O(nlogn)$
 
向堆中插入一个数
- 将欲添加元素添加至堆的最后。
 
- 将该元素向上调整至合适的位置。
 
求堆顶元素
删除堆顶元素
- 把最后一个元素覆盖堆顶元素
 
- 删除最后一个元素,缩小数据规模
 
- 之后将第一个元素向下调整
 
删除任意一个元素
修改任意一个元素
- 修改第k个元素
 
- 然后将第k个元素分别向上/向下调整。
 
堆排序
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
  | 
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
int h[N], cnt, n, m;
void down(int idx){
    int t = idx;
    if(idx * 2 <= cnt && h[idx * 2] < h[t]) t = idx * 2;
    if(idx * 2 + 1 <= cnt && h[idx * 2 + 1] < h[t]) t = idx * 2 + 1;
    swap(h[t], h[idx]);
    if(t != idx){
        down(t);
    }
}
void up(int idx){
    int t = idx;
    if(idx / 2 > 0 && h[idx / 2] > h[t])	t = idx / 2;
    swap(h[t], h[idx]);
    if(t != idx){
        up(t)
    }
}
int popTop(){
    int ret = h[1];
    swap(h[cnt], h[1]);
    cnt--;
    down(1);
    
    return ret;
}
// 建堆过程,向下调整
// 时间复杂度O(n)
void creatHeap(){
    cnt = n;
    for(int i = n / 2; i >= 1; i--){
        down(i);
    }
}
int main(){
    
    cin >> n >> m;
    
    for(int i = 1; i <= n; i++) cin >> h[i];
    
    creatHeap();
    
    for(int i = 1; i <= m; i++){
        cout << popTop() << ' ';
    }
    
    return 0;
    
}
  |