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

优先队列(堆)——二叉堆的实现

2013-09-08 19:57 567 查看
一般数据结构中的堆指的是二叉堆(Binary heap)。堆是一棵完全二叉树,可用数组来表示。对于数组中任意位置i上的元素,其左儿子在位置2i上,右儿子在左儿子后的单元(2i+1)中,它的父亲在位置[i/2](整数除法)上。

在堆实现过程中下表为0的元素作为标记(这个值必须小于其中的任何一个值),用标记只是为了减少判断次数。

fatal.h定义错误处理

#include <stdio.h>
#include <stdlib.h>

#define Error(Str) fprintf(stderr, "%s\n", Str),exit(1)
#define FatalError(Str) Error(Str)


binheap.h函数声明

typedef int ElementType;

#ifndef BINHEAP_H
#define BINHEAP_H

typedef unsigned int Position;
struct HeapStruct
{
int Capacity;
int Size;
ElementType *Elements;
};

typedef struct HeapStruct *PriorityQueue;

PriorityQueue Initialize(int MaxElements);//初始化堆
void Destory(PriorityQueue H);//销毁堆
int IsFull(PriorityQueue H);//是否已满
int IsEmpty(PriorityQueue H);//是否为空
void MakeEmpty(PriorityQueue H);//清空堆
void Insert(ElementType X, PriorityQueue H);//插入元素
ElementType DeleteMin(PriorityQueue H);//删除根
ElementType FindMin(PriorityQueue H);//查找最小值
void Delete(Position P, PriorityQueue H);//删除任意节点
void DecreaseKey(Position P, ElementType Delta, PriorityQueue H);//降低关键字值Delta
void IncreaseKey(Position P, ElementType Delta, PriorityQueue H);//增加关键字值Delta
PriorityQueue BuildHeap(ElementType A[], int N);//构建堆

#endif
binheap.c函数实现
#include "fatal.h"
#include "binheap.h"
#include <stdlib.h>

#define MinPQSize (10)
#define MinData (-32767)

PriorityQueue Initialize(int MaxElements)
{
PriorityQueue H;

if(MaxElements < MinPQSize)
{
Error("Priority queue size too small");
return NULL;
}
H = (PriorityQueue)malloc(sizeof(struct HeapStruct));
if(H == NULL)
FatalError("Out of space");
H->Elements = (ElementType *)malloc(sizeof(ElementType) * (MaxElements + 1));//多申请一个空间用用作标记
if(H->Elements == NULL)
FatalError("Out of space");
H->Capacity = MaxElements;
H->Size = 0;
H->Elements[0] = MinData;//0号元素作为标记
return H;
}

void Destory(PriorityQueue H)
{
free(H->Elements);
free(H);
}

int IsFull(PriorityQueue H)
{
return H->Size == H->Capacity;
}

int IsEmpty(PriorityQueue H)
{
return H->Size == 0;
}

void MakeEmpty(PriorityQueue H)
{
H->Size = 0;
}

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;
}

ElementType FindMin(PriorityQueue H)
{
if(IsEmpty(H))
{
Error("Priority queue is empty");
return H->Elements[0];
}
return H->Elements[1];
}

static void PercolateDown(int n, PriorityQueue H)//下滤
{
int i, child;
ElementType Tmp;

Tmp = H->Elements
;
for(i = n; i * 2 <= H->Size; i = child)
{
child = i * 2;
if(child != H->Size && H->Elements[child + 1] < H->Elements[child])
child++;
if(Tmp > H->Elements[child])
H->Elements[i] = H->Elements[child];
else
break;
}
H->Elements[i] = Tmp;
}

static void PercolateUp(int n, PriorityQueue H)//上滤
{
int i;
ElementType Tmp;

Tmp = H->Elements
;
for(i = n; H->Elements[i] < H->Elements[i/2]; i /= 2)
H->Elements[i] = H->Elements[i/2];
H->Elements[i] = Tmp;
}

void Delete(Position P, PriorityQueue H)//降低关键字的值,使它小于根节点然后删除根节点即可完成该操作
{
DecreaseKey(P, H->Elements[P], H);
DeleteMin(H);
}

void DecreaseKey(Position P, ElementType Delta, PriorityQueue H)//降低关键字的值后采用上滤,将节点上调
{
H->Elements[P] -= Delta;
PercolateUp(P, H);
}

void IncreaseKey(Position P, ElementType Delta, PriorityQueue H)//增加关键字的值后采用下滤
{
H->Elements[P] += Delta;
PercolateDown(P, H);
}

PriorityQueue BuildHeap(ElementType A[], int N)
{
PriorityQueue H;
int i;

H = Initialize(N);
for(i = 1; i <= N; i++)
H->Elements[i] = A[i-1];
H->Size = H->Capacity;
for(i = N / 2; i > 0; i--)
PercolateDown(i, H);
return H;
}
testmain.c测试
#include <stdio.h>
#include <stdlib.h>
#include "binheap.h"

#define N 15

int main(void)
{
PriorityQueue H;
int arr
= {10,12,1,14,6,5,8,15,3,9,7,4,11,13,2};
int i;

H = Initialize(N);
for(i = 0; i < N; i++)//插入法新建堆
Insert(arr[i], H);
for(i = 1; i <= N; i++)
printf("%d ", H->Elements[i]);
printf("\n");
Delete(3, H);//删除跟的右孩子
printf("after delete(%d):\n", 3);
for(i = 1; i < N; i++)
printf("%d ", H->Elements[i]);
printf("\n");
Destory(H);
H = BuildHeap(arr, N);//新建完全二叉树,然后调整为堆,时间复杂度为O(N)
for(i = 1; i <= N; i++)
printf("%d ", H->Elements[i]);
printf("\n");
system("Pause");
return 0;
}

运行结果分析

插入法新建堆,如下图所示:



线性时间构建堆,如下图所示:



程序运行结果,层序输出结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息