堆——笔记

堆是一种二叉树的的结构,并且满足一个节点存储的值必须小于他的两个子节点这种关系

堆的大致模型
存储方式
可以使用一维数组来存储一颗二叉树;比如节点x,他的两个子节点分别是2x和2x+1。
注意这里x的下标是从1开始,从0开始的话2*0仍然是0;

根据这个规则,堆可以进行以下的操作:
1.寻找最小值 也就是树根;

2.插入一个元素,在堆的末尾插入,然后再根据堆的排序规则放置到合适的位置;

3.删除最小值,因为使用一维数组存储,所以删除最小值时无法直接删除,可以将末尾的值把最小值覆盖掉,然后再将末尾的值调整到合适的位置

这里就涉及到调整位置的函数,down和up,即向上调整和向下调整。

//down函数:
int h[N],size;
void down(int n){
	int m=n;//将节点n存储
	if(m*2<=size and h[n]>h[m*2]) n=m*2;//进行比较
	if(m*2+1<=size and h[n]>h[m*2+1]) n=m*2+1;
	if(n!=m){
	swap(h[n],h[m]);//假如n的值已经改变也就意味着进行了调整,就进行交换(这时候n的值已经改变)
	down(n);//接着进行下一次操作,走到最后一个节点的时候自动停止
	}
	return}
//up函数
void up(int n){
	while(n/2 and h[n/2]>h[n]) swap(h[n],h[n/2]),n/=2;//当n/2存储的值比n的值大的时候只需要交换即可
	return;
}

**堆的初始化:**按照堆的规则进行初始化

因为堆的最后一层,也就是倒数第二层的左右子节点,是满足堆的规则的,这时候只需要从n/2(节点总个数为n)的节点开始依次向上调整。

for(int i=n/2;i;i--) down(i);

堆排序:
给出一串数字进行排序;
这个过程就是先把堆进行初始化然后再依次删除掉最小值的过程。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int heap[N],Size;//size为节点个数
void down(int n){//down函数
    int m=n;
    if(m*2<=Size and heap[n]>heap[m*2]) n=m*2;
    if(m*2+1<=Size and heap[n]>heap[m*2+1]) n=m*2+1;
    if(m!=n){
        swap(heap[n],heap[m]);
        down(n);
    }
}
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>heap[i];
    Size=n;
    for(int i=n/2;i;i--) down(i);//初始化
    while(n--){
        printf("%d ",heap[1]);
        heap[1]=heap[Size];//用堆尾元素将最小值覆盖
        Size--;//已经删除掉最小值,节点个数-1;
        down(1);//调整位置;
    }
    return 0;
}
//STL堆排序
#include<bits/stdc++.h>
	using namespace std;
	int main(){
    	int n,x;
    	cin>>n;
    	priority_queue<int,vector<int>,greater<int>>h;
    	for(int i=0;i<n;i++){
        	cin>>x;
        	h.push(x);
    	}
    	while(n--){
        	cout<<h.top()<<" ";
        	h.pop();
    	}
    	return 0;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值