最大堆的操作 (个人笔记整理)

最大堆的最常用表示是一棵二叉树,不特指的话,它是一棵完全二叉树。

最大堆的特性
1、结构特性: 用数组表示完全二叉树
2、部分有序性: 任一结点的值大于等于其子结点的值(兄弟节点之间没有约束)

(基本概念什么的就不多说了,直接上代码)

最大堆的操作集

MaxHeap CreatHeap (int MaxSize)    //最大堆的创建,最大长度为MaxSize ;
bool IsFull (MaxHeap H)		//判断堆是否已满 ;
bool Insert (MaxHeap H, ElementType X)		//插入元素;
bool IsEmpty (MaxHeap H)	//判断堆是否为空 ;
ElementType DeleteMax (MaxHeap H)	//删除并返回堆顶元素; 

最大堆的结构如下

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

建立最大堆

#define MAXDATA 1000 
MaxHeap CreatHeap (int MaxSize){
	//从数组下标为 1的位置储存数据
	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;	//定义 “哨兵 ”,需大于堆中其他所有值;
	/*  哨兵可以让堆的插入代码更简洁优美  */
	return H; 
} 

最大堆的插入操作

bool IsFull (MaxHeap H){
	return (H->Size==H->Capacity);	//当前元素个数达到最大容量,说明已满
}

bool Insert (MaxHeap H, ElementType X){
	int i;
	if(IsFull(H)){
		printf("最大堆已满");
		return false; 
	}
	i = ++H->Size; 	//让i指向堆中最后一个元素位置
	for( ;H->Data[i/2]<X; i/=2)
		H->Data[i] = H->Data[i/2] ;		//上滤 x
	H->Data[i] = X;
	/*上滤即比较x与最后一个结点i的父结点,若小于父结点则把x 放在 i的位置,若大于父结点,
	把原父结点的值放在结点i的位置,如此不断顺着父结点到根节点的路径向上比较 */
	return true;
}

最大堆的删除操作

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

#define ERROR -1	//标识错误
// 删除操作要比插入复杂些 
//是用最大堆中最后一个元素从根节点开始向上过滤下层结点
ElementType DeleteMax (MaxHeap H){
	int Parent, Child;
	ElementType MaxItem, X;
	if(IsEmpty(H)){
		printf("最大堆已空");
		return ERROR; 
	}
	MaxItem = H->Data[1];	//取出根节点存放的最大值
	X = H->Data[H->Size--];	//减小堆的规模,x是堆中最后一个元素
	for(Parent=1; Parent*2<=H->Size; Parent=Child){  //Parent*2<=H->Size  判断该结点有没有子结点
		Child = Parent*2;	//Parent 为父结点,Child为子结点
		if((Child!=H->Size)&&(H->Data[Child]<H->Data[Child+1]))
			Child++;	//Child指向子结点中的较大者
		if(X>=H->Data[Child])
			break;	//若x大于结点Parent的两个子结点,则跳出把x放在Parent的位置
	/*  否则把子结点中较大的元素上移到父结点的位置,再以该子结点作为父结点下滤 x*/
		else
			H->Data[Parent] = H->Data[Child]; 
	} 
	H->Data[Parent] = X;
	
	return MaxItem;		//返回堆顶元素
}

建立最大堆
此处的建立是指如何让将数组中已存在的N个元素按照最大堆的要求存放,(可以调用前面的插入函数,但用以下算法时间代价更小)

void PercDown (MaxHeap H, int p){
	/*  下滤,将H中以 H->Data[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++;
		if(H->Data[Child]<=X)
			break;
		else
			H->Data[Parent]=H->Data[Child];
	}
	H->Data[Parent]=X;
}

void BuildHeap (MaxHeap H){
	//调整 H->Data[]中的元素使满足最大堆的有序性
	//这里假设所有的 H->Size 个元素已经在 H->Data[]中 
	int i;
	//从最后一个元素的父结点开始,直至根节点
	for(i=H->Size/2;i>0;i--)
		PercDown(H, i);
}

下面给出一个用法这种方法建立最大堆的例子

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

typedef struct HNode* Heap;		//堆的类型定义 
typedef int ElementType ;
struct HNode{
	ElementType *Data;		//储存元素的数组 
	int Size;		//堆中当前元素个数 
	int Capacity;	//堆的最大容量 
};
typedef Heap MaxHeap;	//最大堆 
#define MAXDATA 1000 
MaxHeap CreatHeap (int MaxSize){
	/*   在这里稍微改了下CreatHeap()函数  */
	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;	//定义 “哨兵 ”,需大于堆中其他所有值;
	for(H->Size=1;H->Size<=MaxSize;H->Size++){
		scanf("%d",&(H->Data[H->Size]));
	}
	H->Size--;	
	/*由于H->Size表示当前元素个数,且正好是数组最后一个值的下标,
	但for循环结束后H->Size的值为数组最后一个值的下标+1,所以要做 -1 处理*/
	return H; 
} 
void PercDown (MaxHeap H, int p){
	/*  下滤,将H中以 H->Data[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++;
		if(H->Data[Child]<=X)
			break;
		else
			H->Data[Parent]=H->Data[Child];
	}
	H->Data[Parent]=X;
}

void BuildHeap (MaxHeap H){
	//调整 H->Data[]中的元素使满足最大堆的有序性
	//这里假设所有的 H->Size 个元素已经在 H->Data[]中 
	int i;
	//从最后一个元素的父结点开始,直至根节点
	for(i=H->Size/2;i>0;i--)
		PercDown(H, i);
}

int main(void){
	int k;
	MaxHeap H=CreatHeap ( 10);
	for(k=0; k<H->Size; k++)
		printf("%d ",H->Data[k+1]);
	printf("\n");
	BuildHeap(H);
	for(k=0; k<H->Size; k++)
		printf("%d ",H->Data[k+1]);	//下标为0处存的是哨兵,所以1~Size才是有用的数据
	printf("\n");
	free(H);
	return 0;
} 

最小堆的相关操作和最大堆操作的方法一致,只需微小改动,可以自己尝试一下。最大堆的笔记就先整理这么多了,若有错误之处,希望大家不吝指正。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值