堆以及堆排序

  • 如何手写一个堆 堆用于维护数组集合

  • 操作:

操作代码
插入一个数heap[++size] = x (在整个堆的最后一个位置插上x) up(size) (不断往上移)
求集合中的最小值heap[1]
删除最小值heap[1] = heap[size]; (用堆的最后一个元素来覆盖堆顶元素) size–;(把移动过来的最后一个点删除) down(1);(让移动过来的1号点往下走直到找到合适的位置)
删除任意一个元素heap[k] = heap[size]; size–; down(k); up(k); (k的位置可能是需要down() 也可能是需要up() 直接两个都写,一定会执行其中之一,且只会执行其中之一)
修改任意一个元素heap[k] = x; down(k); up(k);
  • 结构:完全二叉树(除最后一层节点,上面是满的,最后一层节点从左到右分布)

  • 堆的性质:

    • 小根堆:每一个点都小于等于左右子节点(递归)— 根节点是所有数据中的最小值
  • 堆的存储:

    • 一维数组存储
    • 1号点是根节点,下标从1开始
    • 节点 x 的左儿子是 2x,右儿子是 2x + 1
  • 堆的基本操作:

    • down(x) 往下调整 时间复杂度O(logn)
      • 基本逻辑:从根节点开始,在其左右子节点中找到最小的节点,将最小的节点与根节点交换,一直移动到没有更小的值在其下面
    • up(x) 往上调整 时间复杂度O(logn)
      • 基本逻辑:从叶子节点开始,只需要与父节点比较(不需要与兄弟节点比较),如果比父节点小,则交换
  • 建立堆(时间复杂度为O(n))

    直接从 n/2 down() 到 n (n/2开始就是不看最后一排)


堆排序

代码:

#include<stdio.h>
#define N 100005
 
int n, m;
int h[N], size;//size记录总个数 

void down(int u) {
	int min = u;
	int t; 
	if(u*2 <= size && h[u*2] < h[min]) {
		min = u*2;
	}
	if(u*2 + 1 <= size && h[u*2 + 1] < h[min]) {
		min = u*2 + 1;
	}
	if(min != u) { 
		t = h[min];//是数去交换,不是指数
		h[min] = h[u];
		h[u] = t;
		down(min);
	}
	return;
}

int main() {
	scanf("%d%d", &n, &m);
	int i;
	for(i = 1; i <= n; i++) {
		scanf("%d", &h[i]);
	}
	size = n;
	
	for(i = n / 2; i >= 1; i--) {
		down(i);//将数组排序 
	}
	
	while(m--) {
		printf("%d ", h[1]);
		h[1] = h[size--];
		down(1);//每次把第一个数和最后一个交换,然后将第一个数往下排序放到正确位置 
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值