数据结构学习过程中,了解了最大堆最小堆的知识,现自己根据理解实现了最大堆。
对于实现最大最小堆,我总结了以下我可能会犯错的几点:
1、最大最小堆利用完全二叉树来实现,注意完全二叉树的左对齐性质,还有所有子节点均小于(或大于)父节点的性质;
2、实现用到的数组,0位置不存放需要插入的元素,在0位置放置一个极大值(或极小值),可以充当哨兵作用。如果0位置放置了需要插入的元素,则会影响父子节点之间位置关系的运算,不满足parent = child / 2,给操作带来麻烦;
3、注意理解上滤概念,理解上滤在插入和删除中的用法。
以下是实现和测试过程,最小堆的实现与最大堆基本一致,改变判别条件即可:
.h文件
typedef int ElemType;
#define FALSE 1000000 //用作0位置存储值,也用作删除判断
class MaxHeap {
public:
//默认构造函数
MaxHeap();
//有参构造函数
MaxHeap(int max);
//析构函数
~MaxHeap();
//1、判断是否为空
bool IsEmpty();
//2、判断是否已满
bool IsFull();
//3、插入元素
bool Insert(ElemType x);
//4、删除最大元素
ElemType DeleteMax();
//打印测试
void printHeap();
private:
ElemType* Heap; //堆数组头指针
int MaxSize; //堆的最大容量
int HeapSize; //堆的大小
};
.cpp文件
//默认构造函数,默认堆的大小为100
MaxHeap::MaxHeap() {
this->MaxSize = 100;
//因为0位置不放元素,所以申请101个空间
this->Heap = new ElemType[101];
this->HeapSize = 0;
this->Heap[0] = FALSE;
}
//有参构造函数,参数为堆的最大容量
MaxHeap::MaxHeap(int max) {
this->MaxSize = max;
this->Heap = new ElemType[max + 1];
this->HeapSize = 0;
this->Heap[0] = FALSE;
}
MaxHeap::~MaxHeap() {
delete[] Heap;
}
//1、判断是否为空
bool MaxHeap::IsEmpty() {
if (this->HeapSize == 0) return true;
return false;
}
//2、判断是否已满
bool MaxHeap::IsFull() {
if (this->HeapSize == this->MaxSize) return true;
return false;
}
//3、插入元素
bool MaxHeap::Insert(ElemType x) {
//如果堆已满,插入失败
if (IsFull()) {
cout << "堆已满" << endl;
return false;
}
//先将要插入元素放入空穴中
this->HeapSize++; //大小加1,方便下面创建空穴
this->Heap[this->HeapSize] = x; //先将插入元素存入空穴
//上滤替换到一个合适位置
for (int i = this->HeapSize; x > this->Heap[i/2]; i = i / 2) {
ElemType temp = this->Heap[i/2];
this->Heap[i / 2] = this->Heap[i];
this->Heap[i] = temp;
}
return true;
}
//4、删除元素
ElemType MaxHeap::DeleteMax() {
//如果堆为空,返回0位置最大值
if (IsEmpty()) return FALSE;
//将最大元素取出,最后返回
ElemType Max = this->Heap[1];
//最大值位置处放入最后一个节点元素,然后逐步向下过滤,找到合适位置
this->Heap[1] = this->Heap[this->HeapSize];
this->HeapSize--; //逻辑删除
//进行逐步过滤
int child;
for (int i = 1; i * 2 < this->HeapSize; i = child) {
//先找到两个子节点中更大的那个位置
if (i * 2 != this->HeapSize && this->Heap[i * 2] < this->Heap[i * 2 + 1])
child = i * 2 + 1;
else
child = i * 2;
//如果该元素小于两个子节点中最大值,进行交换
if (this->Heap[i] < this->Heap[child]) {
ElemType temp = this->Heap[i];
this->Heap[i] = this->Heap[child];
this->Heap[child] = temp;
}
else break; //如果不小于,说明位置合适,终止循环
}
return Max;
}
//打印测试
void MaxHeap::printHeap() {
for (int i = 1; i <= this->HeapSize; i++)
{
cout << this->Heap[i] << " ";
}
cout << endl;
}
测试代码:
int main() {
MaxHeap heap(50);
heap.Insert(10);
heap.Insert(23);
heap.Insert(20);
heap.Insert(9);
heap.Insert(15);
heap.printHeap();
while (!heap.IsEmpty()) {
heap.DeleteMax();
heap.printHeap();
}
return 0;
}
测试结果: