二叉堆

二叉堆:性质为任意一个节点若其右儿子,则其儿子必均大于或小于该节点。(对于同一个堆,大则都大,小则都小,分别称为大根堆,小根堆)

堆的几本操作包括插入和删除。

插入:先假设将新节点插在整个堆(树)的末尾,然后比较其与其父节点的大小,对于小根堆来说,若其小于其根,则其交换其与根的位置。以新节点当前位置为初始位置,继续比较其与其新根大小,直到其小于其根为止。(整个过程被称为上滤)

删除:首先删除指定节点,被删除后的节点称为空穴。若空穴有两个儿子,则选其较小儿子(对于小根堆来说),与其交换位置;若空穴只有一个儿子。容易知道只有一个儿子意味着该儿子即为堆末尾,所以直接交换该儿子与空穴位置即可;若空穴没有儿子,可知已经到了堆底,此时,若空穴位于堆尾,则结束,若不在堆尾,则比较其父与堆尾元素的大小,取较小者成为其父,并将较大者置入空穴。


头文件:

#ifndef BINARYHEAP_H
#define BINARYHEAP_H

typedef int ElemType;
typedef struct{
	ElemType * elemArray; //存储关键字的数组,第一个元素不放关键字
	int maxsize; //堆的最大节点数
	int size; //堆的当前节点数
}BHeap, * PtrToBHeap;

void InitBHeap(BHeap & BH, int Msize); //二叉堆初始化
void MakeEmpty(BHeap & BH); //置空二叉堆
void Insert(BHeap & BH, ElemType E); //插入E,并恢复堆使之保持堆序性
ElemType DeleteMin(BHeap & BH); //删除堆中最小元(堆顶),并恢复堆使之保持堆序性
ElemType FindMin(BHeap BH); //返回堆中最小元(堆顶)
bool IsEmpty(BHeap BH); //检测堆是否为空
bool IsFull(BHeap BH); //检测堆是否已满
void PrintBHeap(BHeap BH); //按照数组顺序依次打印节点的关键字key
void Test(BHeap BH); //检测堆是否保持堆序性

#endif


实现文件:

#include "BinaryHeap.h"
#include <iostream>
using namespace std;

void InitBHeap(BHeap & BH, int Msize)
{
	BH.maxsize = Msize;
	BH.size = 0;
	BH.elemArray = new ElemType[Msize + 1]; //elemArray[0]不存储关键字,故需要Msize + 1个空间
	BH.elemArray[0] = -1;
}

void MakeEmpty(BHeap & BH)
{
	for (int i = BH.maxsize; i > 0; i++){
		BH.elemArray[i] = -1;
	}
	BH.size = 0;
}

void Insert(BHeap & BH, ElemType E)
{
	if (IsFull(BH)){
		cout << "堆已满,插入失败" << endl;
		return;
	}

	int i;
	BH.size++; //堆的当前节点数+1
	for (i = BH.size; BH.elemArray[i / 2] > E; i /= 2){
		BH.elemArray[i] = BH.elemArray[i / 2];
	}
	BH.elemArray[i] = E;
}

ElemType DeleteMin(BHeap & BH)
{
	if (IsEmpty(BH)){
		cout << "堆为空,删除失败" << endl;
		return -1;
	}

	ElemType minElem = BH.elemArray[1];
	int child = 0; //child用于存储2i与2i+1下标对应key值比较小的下标,即空穴下标值
	for (int i = 1; 2 * i <= BH.size; i = child){//跳出条件为i节点没有儿子
		if (2 * i != BH.size && BH.elemArray[i * 2] > BH.elemArray[i * 2 + 1]){
			BH.elemArray[i] = BH.elemArray[i * 2 + 1];//条件2 * i != BH.size用于表明每个节点都有两个儿子
			child = i * 2 + 1;
		}
		else {//若i节点只有一个左儿子或者左儿子key小于右儿子
			BH.elemArray[i] = BH.elemArray[i * 2];
			child = i * 2;
		}
	}
	if (child == BH.size){
		BH.elemArray[BH.size] = 0; //这一步也可以拿掉
	}
	else{
		int father = child / 2;
		if (BH.elemArray[father] <= BH.elemArray[BH.size]){
			BH.elemArray[child] = BH.elemArray[BH.size];
			BH.elemArray[BH.size] = 0; //这一步也可以拿掉
		}
		else{
			BH.elemArray[child] = BH.elemArray[father];
			BH.elemArray[father] = BH.elemArray[BH.size];
			BH.elemArray[BH.size] = 0; //这一步也可以拿掉
		}
	}
	BH.size--; //堆的当前节点数-1
	return minElem;
}

ElemType FindMin(BHeap BH)
{
	return BH.elemArray[1];
}

bool IsEmpty(BHeap BH)
{
	if (BH.size == 0){
		return true;
	}
	else{
		return false;
	}
}

bool IsFull(BHeap BH)
{
	if (BH.size == BH.maxsize){
		return true;
	}
	else{
		return false;
	}
}

void PrintBHeap(BHeap BH)
{
	cout << "堆为:";
	for (int i = 1; i <= BH.size; i++){
		cout << BH.elemArray[i] << " ";
	}
}

void Test(BHeap BH)
{
	int flag = 1;
	if (BH.size % 2 != 0){//总节点数为奇数个
		for (int i = 1; 2 * i <= BH.size; i++){
			if (BH.elemArray[i] > BH.elemArray[2 * i] || BH.elemArray[i] > BH.elemArray[2 * i + 1]){
				cout << "堆不满足堆序性" << endl;
				flag = 0;
				break;
			}
		}
	}
	else{
		for (int i = 1; 2 * i + 1 <= BH.size; i++){
			if (BH.elemArray[i] > BH.elemArray[2 * i] || BH.elemArray[i] > BH.elemArray[2 * i + 1]){
				cout << "堆不满足堆序性" << endl;
				flag = 0;
				break;
			}
		}
		if (BH.elemArray[BH.size / 2] > BH.elemArray[BH.size]){
			cout << "堆不满足堆序性" << endl;
			flag = 0;
		}
	}
	if (flag == 1){
		cout << endl;
	}
}



测试文件:

#include"BinaryHeap.h"
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main()
{
	srand((int)time(0));

	BHeap testBHeapOne;//对总节点数为偶数的堆测试
	InitBHeap(testBHeapOne, 10);
	cout << "测试堆testBHeapOne:" << endl;
	cout << "逐个插入后的堆:" << endl;
	for (int i = 1; i <= testBHeapOne.maxsize; i++){
		Insert(testBHeapOne, rand() % 50 + 1);
		PrintBHeap(testBHeapOne);
		Test(testBHeapOne);
	}
	cout << "逐个删除后的堆:" << endl;
	for (int i = 1; i <= testBHeapOne.maxsize; i++){
		PrintBHeap(testBHeapOne);
		Test(testBHeapOne);
		DeleteMin(testBHeapOne);
	}

	cout << endl;

	BHeap testBHeapTwo;//对总节点数为奇数的堆测试
	InitBHeap(testBHeapTwo, 9);
	cout << "测试堆testBHeapTwo:" << endl;
	cout << "逐个插入后的堆:" << endl;
	for (int i = 1; i <= testBHeapTwo.maxsize; i++){
		Insert(testBHeapTwo, rand() % 50 + 1);
		PrintBHeap(testBHeapTwo);
		Test(testBHeapTwo);
	}
	cout << "逐个删除后的堆:" << endl;
	for (int i = 1; i <= testBHeapTwo.maxsize; i++){
		PrintBHeap(testBHeapTwo);
		Test(testBHeapTwo);
		DeleteMin(testBHeapTwo);
	}

	system("pause");
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值