最大堆和最小堆是二叉堆的两种形式。
不失一般性,只讨论根结点为最小层的情况。
插入[编辑]
只需要将节点插在二叉树的最后一个叶子结点位置,然后比较它对它父亲节点的大小,如果大则停止;如果小则交换位置,然后对父亲节点递归该过程直至根节点。复杂度为O(log(n))。
一般来说,插入的位置可以不是最后一个叶子节点,可以作为任意中间节点的孩子节点插入,将这个叶子节点变为中间节点后,按上文所说的方法调整节点顺序以保证维持堆特性不变。
删除[编辑]
要从堆中删除一个节点,用最后一个节点替换掉根节点,然后调整节点顺序以维持堆特性。
堆定义文件:
#ifndef MINHEAP_H
#define MINHEAP_H
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
using std::ostream;
template <typename T>
class MinHeap
{
friend ostream& operator << (ostream& os,const MinHeap<T> &heap)
{
for(int i = 0; i < heap.currentSize; i++)
{
os << heap.heapArray[i] << "\t";
}
return os;
}
private:
T *heapArray;//存放堆数据的数组
int maxSize;//堆所能容纳的最大元素数目
int currentSize;//当前堆中元素数目
void swap(int posx,int posy)//辅助函数,交换位置x和y的元素
{
T temp = heapArray[posx];
heapArray[posx] = heapArray[posy];
heapArray[posy] = temp;
}
void siftDown(int left) //向下筛
{
int currentPos = left; // 标识父结点
int childPos = leftChild (currentPos); // 标识关键值较小的子结点
while (childPos < currentSize)
{ // 过筛
if ((childPos < currentSize-1) && (heapArray[childPos] > heapArray[childPos + 1]))
{
childPos++; // j指向右子结点,也就是元素最小的子节点
}
if (heapArray[currentPos] > heapArray[childPos])
{
swap(currentPos,childPos);
currentPos = childPos;
childPos = leftChild(childPos); // 向下继续调整
}
else
{
break; // 调整到位
}
}
}
void siftUp(int currentPos) //向上调整
{
int parentPos = parent(currentPos);//父节点位置
while(currentPos > 0)//调整到0号位置则应停止
{
if(heapArray[currentPos] < heapArray[parentPos])//向上调整
{
swap(currentPos,parentPos);
currentPos = parentPos;
parentPos = parent(currentPos);
}
else
{
break;//已经到位
}
}
}
void buildHeap()
{
for(int i = currentSize/2 - 1; i >= 0; i--)
{
siftDown(i);//反复调用筛选函数
}
}
public:
MinHeap(const int size) : maxSize(size)
{
if(size <= 0)
{
return;
}
heapArray = new T[maxSize];
currentSize = 0;
/*
//此处进行堆元素的赋值工作
heapArray[0] = 19; //亦可以用插入的办法构造
heapArray[1] = 8;
heapArray[2] = 35;
heapArray[3] = 65;
heapArray[4] = 40;
heapArray[5] = 3;
heapArray[6] = 7;
heapArray[7] = 45;
currentSize = 8;
buildHeap();*/
}
~MinHeap()
{
delete []heapArray;
}
bool isEmpty() const// 如果堆空,则返回真
{
return currentSize == 0;
}
bool isLeaf(int pos) const//是否叶子节点
{
return (pos >= currentSize/2) && (pos <= currentSize-1);
}
int leftChild(int pos) const//返回左孩子位置
{
return 2 * pos + 1;
}
int rightChild(int pos) const//返回右孩子位置
{
return 2 * pos + 2;
}
int parent(int pos) const//返回父节点位置
{
return (pos-1)/2;
}
bool insert(T &newNode)//向堆中插入新元素newNode
{
if(currentSize == maxSize)//堆空间已经满
{
return false;
}
else
{
heapArray[currentSize] = newNode;
siftUp(currentSize);//向上调整
currentSize++;
return true;
}
}
bool remove(int pos, T& node) // 删除给定下标的元素
{
if(pos < 0 || pos > currentSize - 1)
{
return false;
}
node = heapArray[pos];
heapArray[pos] = heapArray[--currentSize];// 用最后的元素值替代删除位置的元素
if(heapArray[pos] < heapArray[parent(pos)])// 当前元素小于父结点,需要上升调整
{
siftUp(pos);
}
else
{
siftDown(pos);//向下筛
}
return true;
}
bool removeMin(T& node) // 删除堆顶的元素
{
/*if(currentSize == 0)
{
cout << "堆为空,无法移除!" << endl;
return false;
}
else
{
node = heapArray[0];
swap(0,--currentSize);//交换堆顶和最后一个元素
if(currentSize > 1)
{
siftDown(0);
}
return true;
}*/
return remove(0,node);
}
};
#endif
测试代码:
#include "MinHeap.h"
int main()
{
MinHeap<int> minheap(8);
cout << "初始化堆:" << minheap << endl;
int Key[] = {19,8,35,65,40,3,7,45} ;
cout << "建堆前:" << endl;
for(int i = 0;i < 8; i++)
{
minheap.insert(Key[i]);
cout<< Key[i] << "\t";
}
cout << endl;
cout << "建堆后:" << endl;
cout << minheap << endl;
int elem;
cout<< "删除给定下标(3)的元素:" << endl;
minheap.remove(3,elem);
cout<< elem << " deleted." << endl;
cout << "现在堆: " << endl;
cout << minheap << endl;
//插入45
cout<< "插入45:" << endl;
minheap.insert(elem);
cout << "现在堆: " << endl;
cout << minheap << endl;
cout << "从堆顶删除最小值:" ;
minheap.removeMin(elem);
cout << elem << endl;
cout << "现在堆: " << endl;
cout << minheap << endl;
system("pause");
return 0;
}