Loading

数据结构-堆

基本概念

堆是一种用数组来实现的完全二叉树。堆分为两种:最大堆(大顶堆)和最小堆(小顶堆),差别在于结点的排序方式。在最大堆中,任一结点的关键字是其子树所有结点的最大值,而在最小堆中,任一结点的关键字是其子树所有节点的最小值。

在此我们暂时只讨论最大堆,也叫做优先队列。

抽象数据类型描述

类型名称:最大堆(MaxHeap)
数据对象集:完全二叉树,每个结点的元素值不小于其子结点的元素值
操作集:最大堆H是MaxHeap类型,元素item是ElementType类型

  • MaxHeap Create(int MaxSize):创建一个空的最大堆
  • bool IsFull(MaxHeap H):判断最大堆H是否已满
  • void Insert(MaxHeap H, ElementType item):将元素item插入最大堆H
  • bool IsEmpty(MaxHeap H):判断最大堆H是否为空
  • ElementType DeleteMax(MaxHeap H):返回H中最大元素(高优先级)

结构体定义

typedef struct HNode *Heap;
struct HNode{
	ElementType *Data;		//存储元素的数组
	int Size;		//堆中当前元素个数
	int Capacity;		//堆的最大容量
};
typedef Heap MaxHeap;		//最大堆
typedef Heap MinHeap;		//最小堆

最大堆的创建

MaxHeap Create(int MaxSize){
	MaxHeap H=(MaxHeap)malloc(sizeof(struct HNode));
	H->Data=(ElementType *)malloc((MaxSize+1)*sizeof(ElementType));
	H->Size=0;
	H->Capacity=MaxSize;
	H->Data[0]=MAXDATA;			//定义哨兵为大于堆中所有可能元素的值  #define MAXDATA 1000

	return H;
}

判断是否为满

bool IsFull(MaxHeap H){
	return (H->Size==H->Capacity);
}

最大堆的插入

把新元素插入最大堆时,先把新元素放在最大堆的末尾,再与父结点比较大小,如果比父结点大,则交换位置,直到小于父结点,便确定好了插入位置。这一过程叫做上滤

void Insert(MaxHeap H, ElementType X){
	int i;
	if(IsFull(H)){
		printf("最大堆已满");
		return;
	}
	i=++H->Size;		//先把新元素放在最大堆的末尾
	for(;H->Data[i/2]<X;i/=2)		//依次与父结点比较
		H->Data[i]=H->Data[i/2];		//上滤X
	H->Data[i]=X;
}

判断是否为空

bool IsEmpty(MaxHeap H){
	return (H->Size==0);
}

最大元素的返回

因为最大堆的最大元素是根结点,如果直接返回根结点的话,整个堆就被删除了,所以我们把最大元素和最大堆的末尾元素交换,返回并删除末尾元素,再对最大堆进行调整。调整的过程叫做下滤(PercDown),具体来说就是从根结点开始,与两个子结点的最大值进行比较,小于便与之交换,知道大于子结点的最大值。

ElementType DeleteMax(Heap H){
	int Parent,Child;
	ElementType MaxItem,X;
	if(IsEmpty(H)){
		printf("最大堆已空");
		return ERROR;		//#define ERROR -1
	}
	MaxItem=H->Data[1];		//取出根结点存放的最大元素
	X=H->Data[H->Size--];		//最大堆的规模-1
	for(Parent=1;Parent*2<=H->Size;Parent=Child){
		Child=Parent*2;
		if((Child!=H->Size)&&(H->Data[Child]<H->Data[Child+1]))
			Child++;		//Child指向左右子结点中的最大值
		if(X>=H->Data[Child])
			break;			//大于子结点,则找到了位置
		else
			H->Data[Parent]=H->Data[Child];		//下滤X
	}
	H->Data[Parent]=X;

	return MaxItem;
}

最大堆的建立

建立最大堆:将已经存在的N个元素按最大堆的要求存放在一个一维数组中。有两种方法

  1. 通过插入操作,将N个元素一个个相继插入到一个初始为空的最大堆中,其时间复杂度为O(NlogN)。
  2. 在线性复杂度下建立最大堆,将N个元素按输入顺序存入,先满足完全二叉树的结构特性,再调整各结点位置,以满足最大堆的有序特性。具体过程则是从最后一个父结点开始,到根结点,依次进行下滤操作。

我们讨论第2种方法。

void PercDown(MaxHeap H, int p);

void BuildHeap(MaxHeap H){
	int i;
	for(i=H->Size/2;i>0;i--)		//从最后一个父结点k开始,到根结点1
		PercDown(H, i);
}

void PercDown(MaxHeap H, int p){
	int Parent,Child;
	ElementType X;

	X=H->Data[p];		//取出父结点存放的值
	for(Parent=p;Parent*2<=H->Size;Parent=Child){
		Child=Parent*2;
		if((Child!=H->Size)&&(H->Data[Child]<H->Data[Child+1]))
			Child++;		//Child指向左右子结点的最大值
		if(X>=H->Data[Child])
			break;			//大于子结点,则找到了位置
		else
			H->Data[Parent]=H->Data[Child];			//下滤X
	}
	H->Data[Parent]=X;		//X放入合适位置
}
posted @ 2020-07-05 18:41  Kinopio  阅读(173)  评论(0编辑  收藏  举报