408数据结构中有时问插入或删除过程中比较了几次
注意哦,以小根堆为例,如果一个节点有两个孩子,那么down时,需先两个孩子比选个小的,再这个节点和小的孩子比,一共两次
如果只有一个孩子,那么就这个节点 和 唯一的孩子比,共一次
手写一个堆
实现功能:
- 插入一个数(STL中可以直接用)
- 求集合当中的最小值(STL中可以直接用)
- 删除最小值(STL中可以直接用)
- 删除任意一个元素(STL中无法直接使用)
- 修改任意一个元素(STL中无法直接使用)
以小根堆为例
堆是一颗完全二叉树
小根堆每一个点都是小于等于左右子节点的
堆是使用一个一维数组存储的
i 号节点的 左儿子是 2i
右儿子是 2i + 1
同理如果一个节点是 x 号
那么 x/2 就是他的父节点
插入操作
插入一个数,我们是把这个数插入到堆数组的末尾
//size是heap当前的存储的元素数量
size = size + 1;
heap[size] = x;
up(x); //up操作是把堆中的一个值不断的向上移动直到合适的位置
注意有时up后可能还得down
删除操作
删除最小值
把堆中最后一个元素覆盖掉堆顶中的元素,然后不断的调整覆盖后的堆顶中的那个元素直到合适的位置
覆盖后再size–; 就好了
之所以这么做,是因为我们的堆是用一个一维数组来存储的,对于一个一维数组,删除头结点是非常困难的,但是删除尾结点是方便的
删除任意一个节点
比如说删除k号节点,就是把堆中最后一个元素的值覆盖到k号节点上,然后在对堆进行调整
修改任意一个值
也是对一个值修改后然后进行调整就好了
例题
这个题使用堆排序来做,那么堆排序就是把一组数建成一个堆,然后每次把堆顶的数输出出来
#include<iostream>
#include<algorithm>
const int N = 100010;
using namespace std;
int n,m;
int heap[N],heap_size;
//向下移动,一定是和左右孩子中较为小的那个换,如果和较大的那个换,把那个较大的换上来,就不满足小根堆性质
void down(int num) //num表示的是元素位置是几号
{
int t = num;
if((2*num)<=heap_size && heap[num]>heap[2*num]) t = num*2;
//所以说这个地方对于2*num+1时要写heap[t]而不是heap[num]就是因为要找到左右孩子中较为小的那个
if((2*num+1)<=heap_size && heap[t]>heap[2*num+1]) t = 2*num + 1;
if(num!=t)//如果num==t说明到了最后一层了,就不需要再进行递归了
{
swap(heap[num],heap[t]);
down(t);
}
}
void up(int u)
{
while(u/2&&heap[u/2]>heap[u])
{
swap(heap[u/2],heap[u]);
u /= 2;
}
}
int main()
{
cin >> n >> m;
for(int i=1;i<=n;i++) cin >> heap[i];
heap_size = n;
//建堆
//因为对于一个有n个节点的完全二叉树,最后一个节点是n/2的孩子,此时这个n/2一定是最后一个非叶子节点
for(int i=n/2;i>0;i--) down(i);
while(m--)
{
cout<<heap[1]<<" ";
heap[1] = heap[heap_size];
heap_size--;
down(1);
}
return 0;
}
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100010;
int heap[N];
int hp[N],ph[N]; //ph存放的是第k个插入数在堆中的位置是什么
//hp存放的是堆里位置为j的数是第几个插入的
int the_size; //记录的是堆中的元素的个数
void heap_swap(int i,int j)
{
swap(ph[hp[i]],ph[hp[j]]);
swap(hp[i],hp[j]);
swap(heap[i],heap[j]);
}
void down(int x)
{
int num=x; //代表了x号节点和他的子节点中最小的那个值的编号
if(2*x<=the_size&&heap[2*x]<heap[num]) num = 2*x;
if(2*x+1<=the_size && heap[2*x+1]<heap[num]) num = 2*x+1;
if(num!=x){
heap_swap(x,num);
down(num);
}
}
void up(int x)
{
while(x/2 && heap[x]<heap[x/2])
{
heap_swap(x,x/2);
x /= 2;
}
}
int main()
{
int m;
cin >> m;
int n=0;
while(m--)
{
string op;
cin >> op;
int k,x;
if(op=="I"){
cin >> x;
the_size++;
n++;
ph[n] = the_size,hp[the_size] = n;
heap[the_size] = x;
up(the_size);
}
else if(op=="PM") cout<<heap[1]<<endl;
else if(op=="DM"){
heap_swap(1,the_size);
the_size--;
down(1);
}
else if(op=="D"){
cin >> k;
int pos = ph[k];
heap_swap(ph[k],the_size);
the_size--;
up(pos);
down(pos);
}
else if(op=="C"){
cin>>k>>x;
heap[ph[k]] = x;
up(ph[k]);
down(ph[k]);
}
}
return 0;
}