堆
堆是一种二叉树的的结构,并且满足一个节点存储的值必须小于他的两个子节点这种关系
堆的大致模型
存储方式:
可以使用一维数组来存储一颗二叉树;比如节点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;
}