堆--优先队列的完全二叉树--采用数组存储模拟实现(浙)

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MaxData 10000
#define ERROR -1 /* 错误标识应根据具体情况定义为堆中不可能出现的元素值 */

typedef struct HeapStruct *MaxHeap;
typedef int ElementType;

struct HeapStruct {
    
    
	ElementType *Elements;//存储堆元素的数组 
	int Size;//堆的当前元素的个数 
	int Capacity;//堆的最大容量 
}; 

//函数声明
bool IsEmpty(MaxHeap H);
bool IsFull(MaxHeap H);

//创建容量为MaxSize的空的堆
MaxHeap Creat(int MaxSize);
//堆的插入操作,将元素插入 最大堆H中,其中H->Elements[0]已经定义为哨兵 
void Insert(MaxHeap H, ElementType item); 
//从最大堆中取出键值为最大的元素,并删除该结点
ElementType DeleteMax (MaxHeap H);

//建造最大堆
/**
	下滤:该函数是将H中以H->Elements[p]为根的子堆调整为最大堆 
*/
void PercDown(MaxHeap H, int p);
//借用PercDown(MaxHeap H, int p)对堆进行调整,保证最大堆的有序性
void BuildHeap (MaxHeap H);

int main(void) {
    
    
	//------------第一部分是对BuildHeap (MaxHeap H)函数的测试----测试数据为:79 66 43 83 30 87 38 55 91 72 49 9 
	printf("--------第一部分是对BuildHeap (MaxHeap H)函数的测试----测试数据为:79 66 43 83 30 87 38 55 91 72 49 9----------- \n\n");
	//创建容量为12(存储数据的数组单元)的堆
	printf("创建容量为13(存储数据的数组单元)的堆,测试数据为12个,写成13是为了后面测试Insert(MaxHeap H, ElementType item)函数做准备\n");
	MaxHeap H; 
	H = Creat(13);
	
	//向该树中插入数据
	printf("向该树中插入数据:\n");
	for (int n = 1; n <= 12; n++) {
    
    
		scanf("%d",&H->Elements[n]); 
	}
	
	//将该树构造成最大堆
	H->Size = 12;
	H->Capacity = 13;
	printf("将该树构造成最大堆:\n");
	BuildHeap (H);
	
	//显示该树结构中的数据顺序
	printf("显示该树结构中的数据顺序:\n");
	for(int i = 1; i <= 12; i++) {
    
    
		printf("%d	",H->Elements[i]);
	} 
	
	//-----第2部分是测试Insert(MaxHeap H, ElementType item)函数,插入数据设置为92--------
	printf("\n\n-----第2部分是测试Insert(MaxHeap H, ElementType item)函数,插入数据设置为100--------\n\n");
	Insert(H, 100); 
	printf("显示该树结构中的数据顺序:\n");
	for(int i = 1; i <= 13; i++) {
    
    
		printf("%d	",H->Elements[i]);
	} 
	
	//----第3部分是对--从最大堆中取出键值为最大的元素,并删除该结点--测试----
	printf("\n\n---第3部分是对--从最大堆中取出键值为最大的元素,并删除该结点--测试----\n\n");
	printf("删除结点的数据为:%d\n",DeleteMax (H));
	printf("显示该树结构中的数据顺序:\n");
	for(int i = 1; i <= 12; i++) {
    
    
		printf("%d	",H->Elements[i]);
	} 
	return 0;
}

//堆空判断
bool IsEmpty(MaxHeap H) {
    
    
	return (H->Size == 0);
}
//堆满
bool IsFull(MaxHeap H) {
    
    
	return (H->Size == H->Capacity);
}
//创建容量为MaxSize的空的堆
MaxHeap Creat(int MaxSize) {
    
    
	MaxHeap H = (MaxHeap)malloc(sizeof(struct HeapStruct));//为该堆分配内存 
	H->Elements = (ElementType*)malloc((MaxSize+1)*sizeof(ElementType));
	//为堆中数组分配内存,为什么要加1呢,因为数组下标为0处为哨兵,MaxSize表示数组可存储元素的个数(不包括哨兵所占存储单元) 
	H->Size = 0;
	H->Capacity = MaxSize;
	H->Elements[0] = MaxData;//定义哨兵:哨兵为大于堆中所有可能的值,便于以后更快操作
	return H; 
} 

//堆的插入操作,将元素插入 最大堆H中,其中H->Elements[0]已经定义为哨兵 
void Insert(MaxHeap H, ElementType item) {
    
    
	int i;
	if (IsFull(H)) {
    
    
		printf("最大堆已满");
		return;		 
	}
	i = ++H->Size;//i指向插入后堆中的最后一个元素的位置 
	for ( ; H->Elements[i/2] < item; i /= 2) {
    
    //如果插入结点的父结点小于插入结点 
		H->Elements[i] = H->Elements[i/2];//将父结点的值赋给该结点,也就是将较小结点的值下移 
	}
	H->Elements[i] = item;//确定结点的位置,注意哨兵在此处的运用 
} 

//从最大堆中取出键值为最大的元素,并删除该结点
ElementType DeleteMax (MaxHeap H) {
    
    
	int Parent,Child;//孩子结点与父结点所对应的下标 
	ElementType MaxItem,Temp;
	if (IsEmpty(H)) {
    
    
		printf("最大堆为空");
		return ERROR;//虽然存入的数据可能为-1,但是但出现"最大堆为空",说明确实是堆空	 
	}
	MaxItem = H->Elements[1];//用数组存储的,要删除最大元素所对应的结点并将该结点所存储的值返回,将值赋给该变量,便于返回 
	Temp = H->Elements[H->Size--];//建立一个临时变量用于存储完全二叉树的最后一个元素 
	for (Parent = 1; Parent*2 <= H->Size; Parent = Child) {
    
    //Parent*2 <= H->Size:判断是否有左儿子 
		Child = Parent * 2;
		if ((Child != H->Size) && (H->Elements[Child] < H->Elements[Child+1])) {
    
    
			/**
				如果Child == H->Size,说明只有左儿子,没有右儿子,那(H->Elements[Child] < H->Elements[Child+1])该条件就无需进行了 
			*/
			Child++;//Child指向左右子结点的较大者 
		} 
		if (Temp >= H->Elements[Child]) {
    
    
			break;
		} else {
    
    
			H->Elements[Parent] = H->Elements[Child];
			/**
				将temp元素向下层移动,此时末尾的元素并没有在最大元素所在位置,但是可以假设在此位置进行理解 
			*/ 
		}
	}
	H->Elements[Parent] = Temp; 
	return MaxItem;
} 

//建造最大堆
/**
	下滤:该函数是将H中以H->Elements[p]为根的子堆调整为最大堆 
*/
void PercDown(MaxHeap H, int p) {
    
    
	int Parent,Child;//构造用于操作堆的父子结点
	ElementType X;
	X = H->Elements[p];//取出根结点存放的值
	for ( Parent = p; Parent*2 <= H->Size;Parent = Child) {
    
    
		Child = Parent * 2;
		if ((Child != H->Size) && (H->Elements[Child] < H->Elements[Child + 1])) {
    
    
			Child++;//将Child指向左右子结点的较大者 
		}
		if (X >= H->Elements[Child]) {
    
    
			break;//找到了合适的位置 
		} else {
    
    
			H->Elements[Parent] = H->Elements[Child];
		} 
	} 
	H->Elements[Parent] = X;
} 

//借用PercDown(MaxHeap H, int p)对堆进行调整,保证最大堆的有序性
void BuildHeap (MaxHeap H) {
    
    
	//假设所有H->Size个元素已经存在H->Elements[]中
	int i;
	//从最后一个结点的父节点开始,遍历调用PercDown(MaxHeap H, int p)函数
	for (i = H->Size/2;i >0; i--) {
    
    
		PercDown(H,i);
	} 
} 

输出结果:

--------第一部分是对BuildHeap (MaxHeap H)函数的测试----测试数据为:79 66 43 83 30 87 38 55 91 72 49 9-----------

创建容量为13(存储数据的数组单元)的堆,测试数据为12个,写成13是为了后面测试Insert(MaxHeap H, ElementType item)函数做准备
向该树中插入数据:
79 66 43 83 30 87 38 55 91 72 49 9
将该树构造成最大堆:
显示该树结构中的数据顺序:
91      83      87      79      72      43      38      55      66      30      49      9

-----第2部分是测试Insert(MaxHeap H, ElementType item)函数,插入数据设置为100--------

显示该树结构中的数据顺序:
100     83      91      79      72      87      38      55      66      30      49      9       43

---第3部分是对--从最大堆中取出键值为最大的元素,并删除该结点--测试----

删除结点的数据为:100
显示该树结构中的数据顺序:
91      83      87      79      72      43      38      55      66      30      49      9
--------------------------------
Process exited after 29.73 seconds with return value 0
请按任意键继续. . .

猜你喜欢

转载自blog.csdn.net/weixin_45846799/article/details/121637248