优先队列和堆到底有什么区别

What's the difference between Priority Queue and Heap?

Posted by Zaki on December 29, 2019

之前一直对优先队列和堆之间的关系有一点点迷惑,昨天整理了堆,堆化以及堆排序的一些内容,今天主要是对于优先队列ADT的一些内容做一些小结,并且清楚优先队列和堆之间的一种关系。

在这浏览这篇博客之前,再温习一遍前文所提到的堆和堆排序

然后我们进入今天的正题。

优先队列

优先队列(Priority Queue)其实就是一种特殊的队列,是一种特殊的数据结构。它的工作就是找出,返回和删除优先队列里的最小(最大)的元素。

insert()函数的实现类似于之前提到的enqueue(),而Delete()函数的实现更像Dequeue()。

优先队列和堆的区别

上篇博客提到的二叉堆只是优先队列的一种实现方式,那如果说优先队列还有哪些实现方式,太多了,二项堆,配对堆,左偏树,斐波那契堆,平衡树,线段树,甚至是二进制分组的vector来实现一个优先队列等等。

比如二项堆和斐波那契堆在之后的博客也会讲述到。

所以说在这儿也就比较清楚了堆和优先队列之间的一种关系。 而二叉堆的堆化以及实现在上一篇的过程已经讲述,就insert()函数来说,插入到树里的元素的位置必须是在整棵树的最后。

如下图红色部分的元素就是新插入到树中的元素。

就Delete()函数来说,则是对于一棵树的最大堆(最小堆)删除它堆顶的位置。最小堆和最大堆的概念前文已经讲述过,这儿就不再叙述。

堆化的过程前面也已经提到过,这儿则直接上代码。

代码部分

####声明和初始化

   typedef int ElementType;
   struct HeapStruct;
   typedef struct HeapStruct *PriorityQueue;
   #define MinPQSize (10)
   #define MinData (-32767)//C语言中的整型取值范围是-32768~32767

    struct HeapStruct
    {
        int Capacity;//能容纳的最大个数
        int Size; //堆中当前元素个数
        ElementType *Elements; //Elements是数组名
    };
    
   PriorityQueue Initialize( int MaxElements )
    {
        PriorityQueue H;

   if( MaxElements < MinPQSize )
      Error( "Priority queue size is too small" );
   
   H = malloc( sizeof( struct HeapStruct ) );
   if( H ==NULL)
   FatalError( "Out of space!!!" );

   /* Allocate the array plus one extra for sentinel */
   H->Elements = malloc( ( MaxElements + 1 )* sizeof( ElementType ) );
   if( H->Elements == NULL )
      FatalError( "Out of space!!!" );

   H->Capacity = MaxElements;
   H->Size = 0;
   H->Elements[ 0 ] = MinData;

   return H;//返回值不要忘了。
   }

####insert()

   void Insert( ElementType X, PriorityQueue H )
    {
        int i;

        if( IsFull( H ) )
        {
            Error( "Priority queue is full" );
            return;
        }

        for( i = ++H->Size; H->Elements[ i / 2 ] > X; i /= 2 ) 
        //当i=H->size+1时,判断是否上面的比你这个大,如果大,就交换,一直到头为止
            H->Elements[ i ] = H->Elements[ i / 2 ];
        H->Elements[ i ] = X;
        //这儿用一个swap函数也是可以的
        }

####DeleteMin()

      ElementType DeleteMin( PriorityQueue H )
     {
        int i, Child;
        ElementType MinElement, LastElement;

      if( IsEmpty( H ) )
        {
      Error( "Priority queue is empty" );
      return H->Elements[ 0 ];
        }
      MinElement = H->Elements[ 1 ];//取出最小值
      LastElement = H->Elements[ H->Size-- ];//数据规模减小

      for( i = 1; i * 2 <= H->Size; i = Child )
        {//当parent为1时,做一个不断向下perc down的过程,把孩子赋给parent
            /* Find smaller child */
      Child = i * 2;
      if( Child != H->Size && H->Elements[ Child + 1 ]
                            < H->Elements[ Child ] )
          Child++;//child指向左右孩子的最小值(如果是最大堆这为大于号)

            /* Percolate one level */
      if( LastElement > H->Elements[ Child ] )
          H->Elements[ i ] = H->Elements[ Child ];
            else
          break;
        }
      H->Elements[ i ] = LastElement;
      return MinElement;
       }

####percdown()

 void PercDown(PriorityQueue H, int p) { //以p为根结点做percdown,调整为最小堆
int Parent, Child;//i和parent一样
ElementType X;//和上面的last_node一样
X = H->Data[p];
for(parent=p; Parent*2<=H->Size; Parent=Child) {
    Child = Parent*2;
    if((Child != H->Size)&&(H->Data[Child]>H->Data[Child+1])) { //如果是最小堆是child<child+1
        Child++;    
    }
    if(X >= H->Elements[Child]) break;
    else {
        H->Elements[Parent] = H->Elements[Child];
    }
 }
 H->Elements[Parent] = X;    }

####buildheap()

 void BuildHeap(PriortyQueue H) {
 int i;
 for(i=H->Size/2; i>0; i--) {
    PercDown(H, i);
     }
   }

####查找

       ElementType FindMin( PriorityQueue H )
      {
        if( !IsEmpty( H ) )
            return H->Elements[ 1 ];
        Error( "Priority Queue is Empty" );
        return H->Elements[ 0 ];
       }

####判断是否为空

      int IsEmpty( PriorityQueue H )
     {
        return H->Size == 0;
     } ####判断是否为满

      int IsFull( PriorityQueue H )
     {
        return H->Size == H->Capacity;
     }

####Destroy()

    void Destroy( PriorityQueue H )
    {
        free( H->Elements );
        free( H );
    }
        for( i = N / 2; i > 0; i-- )
        PercolateDown( i );