2023/4/11总结

优先队列

1.优先队列一般有两个操作,一个是插入队列,一个是弹出最小元素。如图:

2023/4/11总结_第1张图片

2. 这种队列可以用小根堆来实现。因为小根堆的根节点就是一个堆中的最小元素,所以每一次直接弹出根节点即可完成弹出最小元素的弹出操作。每一次从堆中弹出根节点后要把剩下的元素调正成一个新的小根堆。

3.这里将剩下的元素调正成新的小根堆用到的方法是,首先将堆的最后一个元素放到根节点的位置然后进行下滤操作(将一个元素向下调整,按照顺序将他放入他该在的位置)。代码如下:

void siftdown(int i)
//传入一个需要向下调整的结点编号i
{
    int t,flag=0;//flag用于标记是否需要继续向下调整
    //当i结点有儿子(至少有左儿子)并且需要继续调整时就执行循环
    while(i*2<=n&&flag==0)
    {
        //判断i结点与左儿子的关系,用t记录较小结点的编号
        if(h[i]>h[i*2]) t=i*2;
        else t=i;
        //有右儿子,对右儿子也进行讨论
        if(i*2+1<=n)
        {
            //如果右儿子的值更小,更新
            if(h[t]>h[i*2+1]) t=i*2+1;
         } 
         //如果最小的结点编号不是自己,则进行交换
         if(t!=i)
         {
             swap(t,i);
             i=t;
            //更新i为刚才与它交换的儿子结点编号,便于接下来继续向下调整 
          } 
          else flag=1;
          //说明当前的父节点已经比两个子结点都要小,不需要进行调整了 
     } 
 } 

4.弹出的复杂度为O(logN)。

5.插入操作,即为小根堆中的上滤操作。将要插入的元素插入到根的尾部,然后进行向上调整,重新构建成一个堆。此操作的时间复杂度同样是O(logN)。

6.说到这里,其实我们也可以容易得出,堆排序的道理,就是将优先队列里的元素依次弹出。

7.堆排序的代码:

#include"stdio.h"
int h[200];//存放堆的数组
int n;//用于存储堆中元素个数,也就是堆的大小
void swap(int x,int y)
{
    int t;
    t=h[x];
    h[x]=h[y];
    h[y]=t;
} 
void siftdown(int i)
//传入一个需要向下调整的结点编号i
{
    int t,flag=0;//flag用于标记是否需要继续向下调整
    //当i结点有儿子(至少有左儿子)并且需要继续调整时就执行循环
    while(i*2<=n&&flag==0)
    {
        //判断i结点与左儿子的关系,用t记录较小结点的编号
        if(h[i]>h[i*2]) t=i*2;
        else t=i;
        //有右儿子,对右儿子也进行讨论
        if(i*2+1<=n)
        {
            //如果右儿子的值更小,更新
            if(h[t]>h[i*2+1]) t=i*2+1;
         } 
         //如果最小的结点编号不是自己,则进行交换
         if(t!=i)
         {
             swap(t,i);
             i=t;
            //更新i为刚才与它交换的儿子结点编号,便于接下来继续向下调整 
          } 
          else flag=1;
          //说明当前的父节点已经比两个子结点都要小,不需要进行调整了 
     } 
 } 
void creat()
{
    int i;
    //从最后一个非叶节点到第一个结点依次进行向上调整
    for(i=n/2;i>=1;i--)
    {
        siftdown(i);
     } 
}
//删除最大的元素
int deletemax()
{
    int t;
    t=h[1];//用一个临时变量记录堆顶点的值
    h[1]=h[n];//将堆的最后一个点赋值到堆顶
    n--;//堆的元素减少1
    siftdown(1);//向下调整
    return t;//返回之前记录的堆顶点的最大值 
 } 
main()
{
    int i,num;
    scanf("%d",&num);
    for(i=1;i<=num;i++)
    scanf("%d",&h[i]);
    n=num;
    //建堆
    creat();
    //连续n次删除顶部元素,其实就是将数从大到小输出来 
    for(i=1;i<=num;i++) 
    printf("%d ",deletemax()); 
}

你可能感兴趣的:(数据结构)