二叉堆
- 二叉堆简介
二叉堆是优先队列的一种实现方式
同二叉查找树一样,二叉堆也有结构性和堆序性 - 结构性
堆是一棵除底层外完全被填满的树 - 堆序性
使操作被快速执行的性质是堆序性。在这里,我们想实现的是快速找出最小值(最大值),因此最小值(最大值)应该在根上。
所以我们可以得出一个堆序性:在堆中,对于每一个节点X,X的父亲的值应该小于等于(大于等于)X的值。
如果你不知道二叉树这些知识,建议先自行了解这些知识
下面先给出关键的源代码,稍后再作分析
优先队列
- 头文件代码
BinHeap.h
#ifndef BINHEAP_H_INCLUDED
#define BINHEAP_H_INCLUDED
struct HeapStruct;
typedef struct HeapStruct *PriorityQueue;
PriorityQueue Initialize( int MaxElements );
void Destroy( PriorityQueue H );
void MakeEmpty( PriorityQueue H );
void Inser( ElementType X,PriorityQueue H );
ElementType DeleteMin( PriorityQueue H );
ElementType FindMin( PriorityQueue H );
int IsEmpty( PriorityQueue H );
int IsFull( PriorityQueue H );
#endif // BINHEAP_H_INCLUDED
- 具体实现
BinHeap.c
#include <stdio.h>
#include <stdlib.h>
#include "BinHeap.h"
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;
}
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)
H->Elements[ i ] = H->Elements[ i / 2 ];
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 )
{
Child = i * 2;
if( Child != H->Size && H->Elements[ Child + 1 ] < H->Elements[ Child ] )
Child++;
if( LastElement > H->Elements[ Child ] )
H->Elements[ i ] = H->Elements[ Child ];
else
break;
}
H->Elements[ i ] = LastElement;
return MinElement;
}
代码分析
为什么用数组来实现二叉堆
因为“实惠”
因为二叉堆有个特点是:除了最底层,其他层都必须是满的,也就是一棵二叉完全树
比如上图中,一共有十个节点,那么用数组就可以这样来存
1 2 3 4 5 6 7 8 9 10
下标为1-10
那么的节点1的儿子的下标就是2*1,2*1+1
节点5的父亲便是5/2 = 2
这样很方便吧,写起来也简单
Insert操作
插入操作采取的是上滤
首先我们在数组末端开一个空穴,然后把要插入的值放在空穴里面,之后比较空穴的父亲的值和插入的值的大小,
如果父亲的值教大,那么便交换空穴和父亲,一只重复这个操作,直到找到符合条件的位置
DeleteMin操作
删除最小元操作采取的是下滤
下滤和上滤的思路是差不多的,只是过程相反,这里就不多说,留着读者自己思考吧