在最大堆中,最大堆性质是指除了根以外的所有结点i都满足:
A[PARENT(i)]>=A[i]
在最小堆中,最小堆性质是指除了根以外的所有结点i都满足:
A[PARENT(i)]<=A[i]
维护堆的性质
void maxheap(vector<int> &heap,int i,int heapsize)
该函数用于维护最大堆性质的重要过程。这里假定根结点为LEFT(i)和RIGHT(i)的二叉树都是最大堆。思路:通过将heap[i]的值在最大堆中“逐级下降”。
//堆元素的序号习惯从1开始,这样方便计算双亲结点和孩子结点序号
void maxheap(vector<int> &heap,int i,int heapsize) {
int left = i * 2;
int right = i * 2 + 1;
int large;
if (left<=heapsize&&heap[left-1] > heap[i-1])
large = left;
else large = i;
if (right<=heapsize&&heap[right-1] > heap[large-1])
large = right;
//根结点的值比孩子结点的小,交换后接着往下维护最大堆
if (large != i) {
swap(heap[i-1], heap[large-1]);
maxheap(heap, large, heapsize);
}
return;
}
建堆
可以用自底向上的方法利用过程maxheap把一个大小为n=heap.size()的数组转换为最大堆。子数组heap[n/2+1..n]的元素都是树的叶子结点。而叶子结点就可以看作只有一个结点的最大堆。
void buildmaxheap(vector<int> &heap) {
int length = heap.size();
//从最后那个非叶子结点开始调整最大堆
for (int i = length / 2; i > 0; i--) {
maxheap(heap, i,heap.size());
}
}
堆排序算法
堆排序算法利用buildmaxheap将输入数组heap[1..n]建成最大堆。数组中的最大元素总在根结点heap[0]中,现将heap[0]与heap[heap.size()-1]交换。然后再利用buildmaxheap将数组heap[1..n-1]建成最大堆。以此类推,最后数组需要建成最大堆的只有一个元素时,排序完成。
void heapSort(vector<int> &heap) {
buildmaxheap(heap);
int n = heap.size() - 1;
int heapsize = heap.size();
while (n > 0) {
swap(heap[0], heap[n]);
heapsize--;
maxheap(heap, 1, heapsize);
n--;
}
}
优先队列
优先队列的一些基本操作。
//返回队列最大值
int maximumheap(vector<int> &heap) {
return heap[0];
}
//去掉并返回heap的最大值
int extractmaxheap(vector<int> &heap) {
int heapsize = heap.size();
int max = heap[0];
//swap(heap[0], heap[heapsize-1]);
//直接去掉最大值元素,因此不用交换值
heap[0] = heap[heapsize - 1];
heapsize -= 1;
maxheap(heap, 1, heapsize);
heap.erase(heap.end() - 1);
return max;
}
//将第x个元素的关键值增加到key
void increasekeyheap(vector<int> &heap, int x, int key) {
//key值一定不能小于第x个元素
if (key < heap[x - 1]) return;
heap[x - 1] = key;
int i = x;
//不断与其父结点的关键值进行比较,如果比父结点的关键值大则交换关键值
while (i > 1 && heap[i / 2] < heap[i])
{
swap(heap[i / 2], heap[i]);
i = i / 2;
}
return;
}
//插入关键值为key的结点
void insert(vector<int> &heap, int key) {
//先增加一位数组
heap.push_back(key);
increasekeyheap(heap, heap.size(), key);
return;
}