优先队列(堆) - 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
相关文章推荐
- 优先队列(堆) - C语言实现(摘自数据结构与算法分析 C语言描述)
- 队列 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 队列 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 队列 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 队列 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 优先队列(堆) - C语言实现(摘自数据结构与算法分析 C语言描述)
- (数据结构与算法分析 七)------优先队列中的二叉堆的实现( Java语言描述)
- 散列 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 散列 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 散列 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 使用数组实现队列----《数据结构与算法分析---C语言描述》
- AVL(Adelson-Velskii和Landis)树 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 二叉查找树 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 二叉查找树 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 栈及其应用 - C语言实现(摘自数据结构与算法分析 C语言描述)
- AVL(Adelson-Velskii和Landis)树 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 栈及其应用 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 数据结构与算法分析(Java 语言描述)(36)—— 使用两个队列实现一个栈
- 优先队列(priority_queue)的C语言实现代码
- 排序 - C语言实现(摘自数据结构与算法分析C语言描述))