二叉堆满足其结构性,和堆序性。结构性:要求为完全二叉树,即除树的最底层外,树被完全填满,且底层的元素从左向右填充。堆序性:即在堆中要求,对任意元素X,X的父节点的关键字小等于X的关键字,如此得到最小堆。同理可得最大堆。 由于堆序性,因此二叉堆也常称为实现优先队列(Priority Queue)。
在对二叉堆进行操作时需要始终保持其结构性和堆序性。可用数组来实现二叉堆。数组中的元素关系为:i位置上的节点,其左儿子在2i上,右节点在2i+1上,父节点在i/2(取整)上。用数组代替树结构,从而不用包含指针操作。
具体实现代码如下:
Binary_Heap.h:
#ifndef _BINARY_HEAP_
#define __BINARY_HEAP_
class HeapStruct;
typedef HeapStruct* Heap;
typedef int ElementType;
Heap Initialize(int MaxElement);
void Distory(Heap H);
void MakeEmpty(Heap H);
void Insert(ElementType X,Heap H);
ElementType DeleteMin(Heap H);
ElementType FindMin(Heap H);
int IsEmpty(Heap H);
int IsFull(Heap H);
struct HeapStruct {
int Capacity;
int Size;
ElementType *Elements;
};
int MinData=-1;//用于标记
#endif
Binary_Heap.c:
#include "Binary_Heap.h"
#include <stdio.h>
Heap Initialize(int MaxElement)
{
if (MaxElement<=0)
return nullptr;
Heap H=new HeapStruct;
if(nullptr==H)
{
printf("out of Space \n");
return nullptr;
}
H->Elements=new ElementType[MaxElement+1];//第一个元素为MinData标记
if(nullptr==H->Elements)
{
printf("Out of Space \n");
return nullptr;
}
H->Capacity=MaxElement;
H->Size=0;
H->Elements[0]=MinData;
return H;
}
void Distory( Heap H)
{
if(H->Elements!=nullptr)
delete[] H->Elements;
delete H;
}
void MakeEmpty(Heap H)
{
if(H->Elements!=nullptr)
delete[] H->Elements;
H->Elements=nullptr;
H->Size=0;
}
int IsEmpty(Heap H)
{
if(0==H->Size)
return 1;
else
return 0;
}
int IsFull(Heap H)
{
if(H->Size==H->Capacity)
return 1;
else
return 0;
}
//在尾部插入新元素,并进行上滤操作,直到满足堆序性。
//注意:必满显示的交换赋值操作
void Insert(ElementType X,Heap H)
{
if(IsFull(H))
return;
int i;
for( i=++H->Size;H->Elements[i/2]>X;i/=2)//用MinData标记来防止i/2越界
H->Elements[i]=H->Elements[i/2];
H->Elements[i]=X;//避免显示交换的赋值
}
//删除头部的最小元,并对空穴进行下滤操作,直到满足堆序性。
//注:如何避免显示的交换赋值操作
ElementType DeleteMin(Heap H)
{
if(IsEmpty(H))
return H->Elements[0];
int Child ,i;
ElementType TempCell;
ElementType MinElement=H->Elements[1];
ElementType LastElement=H->Elements[H->Size--];
for( i=1;i*2<=H->Size;i=Child)//对空穴进行下滤操作,直到满足堆序性
{
Child=i*2;
if(Child!=H->Size && H->Elements[Child]>H->Elements[Child+1])//有右儿子,且右儿子更小
++Child;
if(LastElement>H->Elements[Child])
H->Elements[i]=H->Elements[Child];
else
break;
}
H->Elements[i]=LastElement;//最后才将该值真正放到空穴中去,避免了显示的交换操作(将两次赋值减少为一次)
return MinElement;
}
ElementType FindMin(Heap H)
{
if(IsEmpty(H))
return H->Elements[0];
else
return H->Elements[1];
}
//简单测试
void main()
{
Heap H=Initialize(20);
int A[]={12,2,21,2,45,4,23,4,19,6,21,31,25,22};
for(int i=0;i<14;++i)
Insert(A[i],H);
for(int i=0;i<14;++i)
A[i]=DeleteMin(H);
for(int i=0;i<14;++i)//将得到的排序后的元素输出。这也正是堆排序的基本思想
printf("%d ",A[i]);
}