二叉堆:性质为任意一个节点若其右儿子,则其儿子必均大于或小于该节点。(对于同一个堆,大则都大,小则都小,分别称为大根堆,小根堆)
堆的几本操作包括插入和删除。
插入:先假设将新节点插在整个堆(树)的末尾,然后比较其与其父节点的大小,对于小根堆来说,若其小于其根,则其交换其与根的位置。以新节点当前位置为初始位置,继续比较其与其新根大小,直到其小于其根为止。(整个过程被称为上滤)
删除:首先删除指定节点,被删除后的节点称为空穴。若空穴有两个儿子,则选其较小儿子(对于小根堆来说),与其交换位置;若空穴只有一个儿子。容易知道只有一个儿子意味着该儿子即为堆末尾,所以直接交换该儿子与空穴位置即可;若空穴没有儿子,可知已经到了堆底,此时,若空穴位于堆尾,则结束,若不在堆尾,则比较其父与堆尾元素的大小,取较小者成为其父,并将较大者置入空穴。
头文件:
#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");
}