ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【刷题】数据结构——堆【模板】

2022-02-01 18:30:36  阅读:167  来源: 互联网

标签:size frac int down swap heap 数据结构 模板 刷题


文章目录

堆的原理

  • 堆是一个完全二叉树

  • 小根堆:父亲比左右儿子小,根节点是最小值
    小根堆:父亲比左右儿子大,根节点是最大值

  • 编号 x x x的左儿子: 2 x 2x 2x,右儿子: 2 x + 1 2x+1 2x+1
    下标从1开始


堆的操作

堆的操作主要有两种:down、up

以小根堆为例:

down:如果编号 x x x如果变得比儿子大,则和较小的儿子进行交换,直到放到合适的位置(两儿子都比它大)。
up:如果编号 x x x如果变得比父亲小,则和父亲交换,直到放到合适的位置(比父亲大)。

// 注意输入的u要合法,不能大于size
void up(int u) {
	while (u > 1 && heap[u] < heap[u / 2]) swap(heap[u], heap[u / 2]), u /= 2;
} 
// 注意输入的u要合法,不能等于0
void down(int u) {
	int t = u;
	while (true) {
		if (u * 2 <= size && heap[u] > heap[u * 2]) t = u * 2;
		if (u * 2 + 1 <= size && heap[t] > heap[u * 2 + 1]) t = u * 2 + 1;
		if (u != t) {
			swap(heap[u], heap[t]);
			u = t;
		}
		else break;
	}
}
  1. 插入一个数
    堆末尾添加一个数,并调整
    heap[ ++ size ] = x;
    up(size);
  2. 求集合中最小值
    就是堆顶
    head[1]
  3. 删除最小值
    用堆末尾替换堆顶,再调整
    head[1] = head[ size -- ];
    down(1);
  4. 删除任意一个元素
    head[k] = head[size -- ]
    down(k)
    up(k)
  5. 修改任意一个元素
    heap[k] = x
    down(k)
    up(k)
  6. 建立堆
    for (int i = 1; i <= n ; i ++ ) head[i] = a[i]; 先给haep随便赋值
    for (int i = n / 2; i ; i -- ) down(i); O ( n ) O(n) O(n)时间进行建堆
    因为最后一层的 n / 2 n / 2 n/2个点都没有孩子,所以不需要down,故 i i i从 n / 2 n / 2 n/2开始
    倒数第二层有 n / 4 n / 4 n/4个点,最多需要down 1次
    倒数第三层有 n / 8 n / 8 n/8个点,最多需要down 2次
    倒数第四层有 n / 16 n / 16 n/16个点,最多需要down 3次


    1 ∗ n 4 + 2 ∗ n 8 + 3 ∗ n 16 + . . . 1 * \frac{n}{4} + 2 * \frac{n}{8} + 3 *\frac{n}{16} + ... 1∗4n​+2∗8n​+3∗16n​+...
    = n ( 1 2 2 + 2 2 3 + 3 2 4 + 4 2 5 + . . . ) =n(\frac{1}{2^2} +\frac{2}{2^3}+ \frac{3}{2^4} + \frac{4}{2^5} + ... ) =n(221​+232​+243​+254​+...)
    令S
    S = 1 2 2 + 2 2 3 + 3 2 4 + 4 2 5 + . . . S=\frac{1}{2^2} +\frac{2}{2^3}+ \frac{3}{2^4} + \frac{4}{2^5} + ... S=221​+232​+243​+254​+...
    左右乘2
    2 S = 1 2 + 2 2 2 + 3 2 3 + 4 2 4 + 5 2 5 + . . . 2S=\frac{1}{2} +\frac{2}{2^2}+ \frac{3}{2^3} + \frac{4}{2^4} + \frac{5}{2^5} + ... 2S=21​+222​+233​+244​+255​+...
    上面两式相减
    2 S − S = 1 2 + 1 2 2 + 1 2 3 + 1 2 4 + 1 2 5 + . . . 2S-S=\frac{1}{2} +\frac{1}{2^2}+ \frac{1}{2^3} + \frac{1}{2^4} + \frac{1}{2^5} + ... 2S−S=21​+221​+231​+241​+251​+...
    S = 1 2 + 1 2 2 + 1 2 3 + 1 2 4 + 1 2 5 + . . . < 1 S=\frac{1}{2} +\frac{1}{2^2}+ \frac{1}{2^3} + \frac{1}{2^4} + \frac{1}{2^5} + ... < 1 S=21​+221​+231​+241​+251​+...<1
    因此该操作次数小于n,是 O ( n ) O(n) O(n)的。

基本的堆

在这里插入图片描述题目链接

#include <iostream>
#include <cstring>
using namespace std;

const int N = 1000005;
int heap[N], size;
int n;

void up(int u) {
	while (u > 1 && heap[u] < heap[u / 2]) swap(heap[u], heap[u / 2]), u /= 2;
} 

void down(int u) {
	int t = u;
	while (true) {
		if (u * 2 <= size && heap[u] > heap[u * 2]) t = u * 2;
		if (u * 2 + 1 <= size && heap[t] > heap[u * 2 + 1]) t = u * 2 + 1;
		if (u != t) {
			swap(heap[u], heap[t]);
			u = t;
		}
		else break;
	}
}

int main() {
	scanf("%d", &n);
	int op;
	int k, x;
	while (n -- ) {
		scanf("%d", &op);
		if (op== 1) {
			scanf("%d", &x);
			heap[ ++ size] = x;
			up(size);
		}
		else if (op == 2) {
			printf("%d\n", heap[1]);
		}
		else {
			heap[1] = heap[size -- ];
			down(1);
		}
	}
	return  0;
}

带映射堆(可对第k个插入元素操作)

在这里插入图片描述
注意这题需要保存第k个插入的数在堆中的映射,同时也要保存堆到第k个插入的数的映射。
因此交换操作和删除操作,也要对这个映射进行操作。

#include <iostream>
#include <cstring>
using namespace std;

const int N = 100005;
int heap[N], size_heap;
int n;
int hp[N]; // 堆 到 第k个插入元素 的 映射 
int ph[N]; // 第k个插入元素 到 堆 的映射 

void heap_swap(int a, int b) {
    swap(heap[a], heap[b]);
    swap(ph[hp[a]], ph[hp[b]]);
    swap(hp[a], hp[b]);
}

void up(int u) {
    while(u > 1 && heap[u] < heap[u / 2]) heap_swap(u, u / 2), u /= 2;
}

void down(int u) {
    int t = u;
    while(true) {
        if (u * 2 <= size_heap && heap[u] > heap[u * 2]) t = u * 2;
        if (u * 2 + 1 <= size_heap && heap[t] > heap[u * 2 + 1]) t = u * 2 + 1;
        if (u != t) {
            heap_swap(u, t);
            u = t;
        }
        else break;
    }
}

int main() {
    scanf("%d", &n);
    char op[2];
    int k, x, cnt = 0;
    while(n -- ) {
        scanf("%s", op);
        if (op[0] == 'I') {
            scanf("%d", &x);
            heap[ ++ size_heap] = x;
            hp[size_heap] = ++ cnt;
            ph[cnt] = size_heap;
            up(size_heap);
        }
        else if (!strcmp(op, "D")) {
            scanf("%d", &k);
            k = ph[k];
            //heap[k] = heap[size_heap -- ]; // 错的,还要对映射操作
            heap_swap(k, size_heap -- );
            up(k);
            down(k);
        }
        else if (!strcmp(op, "C")) {
            scanf("%d%d", &k, &x);
            k = ph[k];
            heap[k] = x;
            up(k); down(k);
        }
        else if (!strcmp(op, "PM")) {
            printf("%d\n", heap[1]);
        }
        else if (!strcmp(op, "DM")) {
            //heap[1] = heap[size_heap -- ]; // 错的,还要对映射操作
            heap_swap(1, size_heap -- );
            down(1);
        }
    }
    return 0;
}

标签:size,frac,int,down,swap,heap,数据结构,模板,刷题
来源: https://blog.csdn.net/qq_42581685/article/details/122764325

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有