您的位置:首页 > 理论基础 > 数据结构算法

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

2015-05-19 17:18 399 查看

一、概述

  优先队列(堆)是允许至少下列两种操作的数据结构: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?

#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

[cpp] view
plaincopyprint?

#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 ]

<H->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

[cpp] view
plaincopyprint?

#include "binheap.h"

#include <stdio.h>

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文件):

[cpp] view
plaincopyprint?

#include <stdio.h>

#include <stdlib.h>

#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
http://blog.csdn.net/shuxiao9058/article/details/7434706
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐