推排序(手写堆)

堆:一个完全二叉树(上层是满的,最后一层从左向右依次排列)

大根堆:每个点都大于等于他的左右儿子,根节点是集合里的最大值
小根堆:每个点都小于等于他的左右儿子,根节点是集合中的最小值

手写堆需要维护的操作:

1.插入一个数(插到数组最后一位然后再调整)
2.求集合中的最小值(头节点)
3.删除一个数(删除后用尾结点填充,再调整)
4.删除一个任意元素( 4 和 5在STL库中的堆结构实现不了 )
5.修改一个任意元素

image

 

手写堆的两个基本操作:

down操作:从根开始,若不符合堆的概念,则进行换位,不断递归直到符合堆

up操作:

以这两个基本操作可以完成维护堆的五个操作

手写堆的实现方式:一维数组

数组的第一个元素表示根节点(下标从1开始)。x的左儿子下标为 2x,右儿子下标为2x+1

例题:

image

 输入样例:

5 3
4 5 1 3 2 

预期输出:

1 2 3

代码实现:

#include<bits/stdc++.h>
using namespace std;

const int N = 1e5+10;
int h[N],size;
int n,m;

void down(int u)
{
    int t = u;//t表示根节点和他的两个儿子之间最小的索引值
    if(u*2<=size &&h[u*2]<h[t]) t=u*2;
    if(u*2+1<=size&& h[u*2+1]<h[t]) t=u*2+1;

    if(u!=t)
    {
        swap(h[u],h[t]);
        down(t);
    }
}
/**
up操作,本题中用不到
void up(int u)
{
  while(u/2 && h[u] < h[u/2])
  {
    swap(h[u),h[u/2)];
    u=u/2;
  }
}
**/ int main() { cin>>n>>m; for(int i=1;i<=n;i++) cin>>h[i]; size =n; //建堆,时间复杂度O(n) for(int i=n/2;i>0;i--) down(i); //输出最小值 while(m--) { printf("%d ",h[1]); h[1]=h[size]; size --; down(1); } }

  

posted @ 2025-09-08 21:59  小花护符  阅读(9)  评论(0)    收藏  举报