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

一、概述

  优先队列(堆)是允许至少下列两种操作的数据结构: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
#ifndef _BinHeap_H typedef int ElementType; struct HeapStruct; typedef struct HeapStruct *PriorityQueue; PriorityQueue Initialize( int MaxElements ); void Destroy( PriorityQueue H ); void MakeEmpty( PriorityQueue H ); void Insert( ElementType X, PriorityQueue H ); ElementType DeleteMin( PriorityQueue H ); ElementType FindMin( PriorityQueue H ); int IsEmpty( PriorityQueue H ); int IsFull( PriorityQueue H ); #endif
文件名:binheap.c
#include "fatal.h" #include "binheap.h" #define MinPQSize (10) #define MinData (-32767) struct HeapStruct { int Capacity; int Size; ElementType *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; } /* H->Elements[ 0 ] is a sentinel */ 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) /* The new element is percolated up the heap */ H->Elements[ i ] = H->Elements[ i / 2 ]; /* until the correct location is found */ H->Elements[ i ] = X; } 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 ) { /* Find smaller child */ Child = i * 2; if ( Child != H->Size && H->Elements[ Child + 1 ] Elements[ Child ] ) Child++; /* Percolate one level */ if ( LastElement > H->Elements[ Child ] ) H->Elements[ i ] = H->Elements[ Child ]; else break; } H->Elements[ i ] = LastElement; return MinElement; } void MakeEmpty( PriorityQueue H ) { H->Size = 0; } 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; } void Destroy( PriorityQueue H ) { free( H->Elements ); free( H ); }
文件名:main.c
#include "binheap.h" #include int main() { PriorityQueue H = Initialize( 50 ); int ar[] = { 32, 21, 16, 24, 31, 19, 68, 65, 26, 13 }; int i; for ( i = 0; i < 10; i++ ) Insert( ar[i], H ); for ( i = 0; i < 10; i++ ) { printf( "%d\n", DeleteMin( H ) ); } return 0; }

附录:上述代码中用到了Error、FatalError等函数,其实现如下(即fatal.h文件):
#include #include #define Error( Str ) FatalError( Str ) #define FatalError( Str ) fprintf( stderr, "%s\n", Str ), exit( 1 )
备注:本文摘自《数据结构与算法分析 C语言描述 Mark Allen Weiss著》,代码经gcc编译测试通过。

附件下载:http://download.csdn.net/detail/shuxiao9058/4212412#binheap_20120407.tar.gz


你可能感兴趣的:(优先队列(堆) - C语言实现(摘自数据结构与算法分析 C语言描述))