优先队列(堆) - C语言实现(摘自数据结构与算法分析 C语言描述)

来源:互联网 发布:php高级程序员面试题 编辑:程序博客网 时间:2024/04/28 09:22

一、概述

  优先队列(堆)是允许至少下列两种操作的数据结构:Insert(插入),它的工作显而易见的,以及DeleteMin(删除最小者),它的工作是找出、返回和删除优先队列中最小的元素。

  如同大多数数据结构那样,有时可能要添加一些操作,但这些添加的操作属于扩展的操作,而不属于图1所描述的基本模型。


图1 优先队列的基本模型

  使操作被快速执行的性质是堆序(heap order)性,由于我们想要快速地找到最小元因此最小元应该在根上。应用这个逻辑我们得到堆序性质。在一个堆中,对于每一个节点X,X的父亲中的关键字小于(或等于)X中的关键字(这种堆叫做最小堆),根节点除外(它没有父亲)。图2中左边的树是一个堆,但是,右边的树则不是(虚线表示堆序性质被破坏)。


图2 两棵完全二叉树(只有左边的树是堆)

  无论从概念上还是实际上考虑,执行这两种所要求的操作都是容易的,只需始终保持堆序性质。

二、实现

  Insert(插入):插入操作一般使用的策略叫做上滤(percolate up):新元素在堆中上滤直到找出正确的位置(设堆为H,待插入的元素为X,首先在size+1的位置建立一个空穴,然后比较X和空穴的父亲的大小,把“大的父亲”换下来,以此推进,最后把X放到合适的位置)。

  DeleteMin(删除最小元):与插入“上滤”相对应,采用一种“下滤”的策略,就是逐层推进,把较小的儿子换上来,这里面有个小的问题在具体算法实现上要注意,设堆的最后一个元素是L,在推进到倒数第二层时,将导致最后一层的某个孩子被换上去而产生一个洞,这时候为了保持堆的结构,必须把最后一个元素运过去补上,此时就存在一个问题,如果L比那个孩子小的话就不能保证堆序的性质了,所以在程序中要加一个if语句来进行这个边界条件的处理,对于一个完整的程序,算法是重要的一方面,而对算法边界问题的处理则是更重要的一方面。

文件名:binheap.h
[cpp] view plaincopyprint?
  1. #ifndef _BinHeap_H  
  2.   
  3. typedef int ElementType;  
  4.   
  5. struct HeapStruct;  
  6. typedef struct HeapStruct *PriorityQueue;  
  7.   
  8. PriorityQueue Initialize( int MaxElements );  
  9. void Destroy( PriorityQueue H );  
  10. void MakeEmpty( PriorityQueue H );  
  11. void Insert( ElementType X, PriorityQueue H );  
  12. ElementType DeleteMin( PriorityQueue H );  
  13. ElementType FindMin( PriorityQueue H );  
  14. int IsEmpty( PriorityQueue H );  
  15. int IsFull( PriorityQueue H );  
  16.   
  17. #endif  

文件名:binheap.c
[cpp] view plaincopyprint?
  1. #include "fatal.h"  
  2. #include "binheap.h"  
  3.   
  4. #define MinPQSize (10)  
  5. #define MinData (-32767)  
  6.   
  7. struct HeapStruct  
  8. {  
  9.     int Capacity;  
  10.     int Size;  
  11.     ElementType *Elements;  
  12. };  
  13.   
  14. PriorityQueue Initialize( int MaxElements )  
  15. {  
  16.     PriorityQueue H;  
  17.   
  18.     if ( MaxElements < MinPQSize )  
  19.         Error( "Priority queue size is too small!" );  
  20.   
  21.     H = malloc( sizeofstruct HeapStruct ) );  
  22.     if ( H == NULL )  
  23.         FatalError( "Out of space!!!" );  
  24.   
  25.     /* Allocate the array plus one extra for sentinel */  
  26.     H->Elements = malloc( ( MaxElements + 1 )   
  27.         * sizeof( ElementType ) );  
  28.     if ( H->Elements == NULL )  
  29.         FatalError( "Out of space!!!" );  
  30.   
  31.     H->Capacity = MaxElements;  
  32.     H->Size = 0;  
  33.     H->Elements[ 0 ] = MinData;  
  34.   
  35.     return H;  
  36. }  
  37.   
  38. /* H->Elements[ 0 ] is a sentinel */  
  39. void   
  40. Insert( ElementType X, PriorityQueue H )  
  41. {  
  42.     int i;  
  43.   
  44.     if ( IsFull( H ) )  
  45.     {  
  46.         Error( "Priority queue is full" );  
  47.         return ;  
  48.     }  
  49.     for ( i = ++H->Size; H->Elements[ i / 2 ] > X; i /= 2) /* The new element is percolated up the heap  */  
  50.         H->Elements[ i ] = H->Elements[ i / 2 ];           /* until the correct location is found */  
  51.     H->Elements[ i ] = X;  
  52. }  
  53.   
  54. ElementType   
  55. DeleteMin( PriorityQueue H )  
  56. {  
  57.     int i, Child;  
  58.     ElementType MinElement, LastElement;  
  59.   
  60.     if ( IsEmpty( H ) )  
  61.     {  
  62.         Error( "Priority queue is empty!" );  
  63.         return H->Elements[ 0 ];  
  64.     }  
  65.     MinElement = H->Elements[ 1 ];  
  66.     LastElement = H->Elements[ H->Size-- ];  
  67.   
  68.     for ( i = 1; i * 2 <= H->Size; i = Child )  
  69.     {  
  70.         /* Find smaller child */  
  71.         Child = i * 2;  
  72.         if ( Child != H->Size && H->Elements[ Child + 1 ]  
  73.                                 <H->Elements[ Child ] )  
  74.             Child++;  
  75.   
  76.         /* Percolate one level */  
  77.         if ( LastElement > H->Elements[ Child ] )  
  78.             H->Elements[ i ] = H->Elements[ Child ];  
  79.         else  
  80.             break;  
  81.     }  
  82.     H->Elements[ i ] = LastElement;  
  83.     return MinElement;  
  84. }  
  85.   
  86. void  
  87. MakeEmpty( PriorityQueue H )  
  88. {  
  89.     H->Size = 0;  
  90. }  
  91.   
  92. ElementType  
  93. FindMin( PriorityQueue H )  
  94. {  
  95.     if( !IsEmpty( H ) )  
  96.         return H->Elements[ 1 ];  
  97.     Error( "Priority Queue is Empty" );  
  98.     return H->Elements[ 0 ];  
  99. }  
  100.   
  101. int  
  102. IsEmpty( PriorityQueue H )  
  103. {  
  104.     return H->Size == 0;  
  105. }  
  106.   
  107. int  
  108. IsFull( PriorityQueue H )  
  109. {  
  110.     return H->Size == H->Capacity;  
  111. }  
  112.   
  113. void  
  114. Destroy( PriorityQueue H )  
  115. {  
  116.     free( H->Elements );  
  117.     free( H );  
  118. }  

文件名:main.c
[cpp] view plaincopyprint?
  1. #include "binheap.h"  
  2. #include <stdio.h>  
  3.   
  4. int   
  5. main()  
  6. {  
  7.     PriorityQueue H = Initialize( 50 );  
  8.     int ar[] = { 32, 21, 16, 24, 31, 19, 68, 65, 26, 13 };  
  9.     int i;  
  10.     for ( i = 0; i < 10; i++ )  
  11.         Insert( ar[i], H );  
  12.     for ( i = 0; i < 10; i++ )  
  13.     {  
  14.         printf( "%d\n", DeleteMin( H ) );  
  15.   
  16.     }  
  17.     return 0;  
  18. }  


附录:上述代码中用到了Error、FatalError等函数,其实现如下(即fatal.h文件):
[cpp] view plaincopyprint?
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3.   
  4. #define Error( Str )        FatalError( Str )  
  5. #define FatalError( Str )   fprintf( stderr, "%s\n", Str ), exit( 1 ) 

0 0
原创粉丝点击