二叉堆定义
二叉堆实现
fatal.h
#include <stdio.h>
#include <stdlib.h>
#define Error( Str ) FatalError( Str )
#define FatalError( Str ) fprintf( stderr, "%s\n", Str ), exit( 1 )
binheap.h
typedef int ElementType;
/* START: fig6_4.txt */
#ifndef _BinHeap_H
#define _BinHeap_H
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
/* END */
binheap.c
#include "binheap.h"
#include "fatal.h"
#include <stdlib.h>
#define MinPQSize (10)
#define MinData (-32767)
struct HeapStruct
{
int Capacity; // 容量上限
int Size; // 当前元素个数
ElementType *Elements; // 存放数据的数组
};
/* START: fig6_0.txt */
PriorityQueue
Initialize( int MaxElements )
{
PriorityQueue H;
/* 1*/ if( MaxElements < MinPQSize )
/* 2*/ Error( "Priority queue size is too small" );
/* 3*/ H = malloc( sizeof( struct HeapStruct ) );
/* 4*/ if( H ==NULL )
/* 5*/ FatalError( "Out of space!!!" );
/* Allocate the array plus one extra for sentinel */
/* 6*/ H->Elements = malloc( ( MaxElements + 1 )
* sizeof( ElementType ) );
/* 7*/ if( H->Elements == NULL )
/* 8*/ FatalError( "Out of space!!!" );
/* 9*/ H->Capacity = MaxElements;
/*10*/ H->Size = 0;
// 第一个位置放一个最小值作为比较的标记位 真正的数据都是从1位置往后开始放置的
/*11*/ H->Elements[ 0 ] = MinData;
/*12*/ return H;
}
/* END */
void
MakeEmpty( PriorityQueue H )
{
H->Size = 0;
}
/* START: fig6_8.txt */
/* H->Element[ 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 )
// 如果一直上滤到某个已经满足堆序性的位置时候 或者 (根节点, 当i迭代到1的时候,由于0位置上的值最小,循环会终止),此时在这个位置插入X值就好,之前的交换把这个可以插入X的空穴一路上升到目标位置
H->Elements[ i ] = H->Elements[ i / 2 ];
H->Elements[ i ] = X;
}
/* END */
/* START: fig6_12.txt */
ElementType
DeleteMin( PriorityQueue H )
{
int i, Child;
ElementType MinElement, LastElement;
/* 1*/ if( IsEmpty( H ) )
{
/* 2*/ Error( "Priority queue is empty" );
/* 3*/ return H->Elements[ 0 ];
}
// 最小值直接取位置1上面的元素就可以了
/* 4*/ MinElement = H->Elements[ 1 ];
// 删除位置1的元素之后会留下一个空穴 我们把最后一个元素放到这里 然后进行下滤
/* 5*/ LastElement = H->Elements[ H->Size-- ];
/* 6*/ for( i = 1; i * 2 <= H->Size; i = Child )
{
/* Find smaller child */
/* 7*/ Child = i * 2;
/* 8*/ if( Child != H->Size && H->Elements[ Child + 1 ]
/* 9*/ < H->Elements[ Child ] )
// 左右子节点取更小的一个作为替换操作对象
/*10*/ Child++;
/* Percolate one level */
/*11*/ if( LastElement > H->Elements[ Child ] )
// 把child位置的值放到i上面 然后 把 i变成 child 等循环结束或者堆序性得到满足的时候 i 就是新的空穴位置
/*12*/ H->Elements[ i ] = H->Elements[ Child ];
else
/*13*/ break;
}
/*14*/ H->Elements[ i ] = LastElement;
/*15*/ return MinElement;
}
/* END */
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 );
}
#if 0
/* START: fig6_14.txt */
for( i = N / 2; i > 0; i-- )
PercolateDown( i );
/* END */
#endif
测试代码
#include "binheap.h"
#include <stdio.h>
#define MaxSize (1000)
main( )
{
PriorityQueue H;
int i, j;
H = Initialize( MaxSize );
for( i=0, j=MaxSize/2; i<MaxSize; i++, j=( j+71)%MaxSize )
Insert( j, H );
j = 0;
while( !IsEmpty( H ) )
if( DeleteMin( H ) != j++ )
printf( "Error in DeleteMin, %d\n", j );
printf( "Done...\n" );
return 0;
}
参考资料: 《数据结构与算法分析: C语言描述》