堆分为最大堆和最小堆,本文以最大堆为例。其实主要就是adjustDown()和adjustUp()这两个操作。一个删除时调整堆,一个插入时调整堆。
#include <bits/stdc++.h>
#define MAX_SIZE 1010
#define INF 99999999
using namespace std;
/*
堆:
1)堆中某个节点的值总是不大于(不小于)其父节点的值
2)堆总是一棵完全二叉树
索引为 0的的地方存放的是哨兵:INF
设孩子结点为 i,父亲结点为 i/2
设父亲结点为 j,孩子结点为 i * 2 和 i * 2 + 1
*/
/*
操作:
0)建堆
1)插入
2)删除
3)获取最大值
*/
class MaxHeap
{
public:
int heap[MAX_SIZE];
int size = 0;
MaxHeap(){ heap[0] = INF; }
};
/*
向下调整:
调整时保证此次调整的根结点的左右孩子都是最大堆
循环:求出孩子中的较大者,和父亲结点比较
父亲结点大,退出;
孩子结点大,孩子结点覆盖父亲结点(向上覆盖)。然后父亲下降到此孩子结点
退出后用最初的父亲结点覆盖现在的父亲结点
*/
void adjustDown(MaxHeap *mh, int index)
{
int p, c, data = mh->heap[index];
for(p = index; p * 2 <= mh->size; p = c)
{
c = p * 2;
if(c != mh->size && mh->heap[c] < mh->heap[c + 1])
c++;
if(data >= mh->heap[c])
break;
else
mh->heap[p] = mh->heap[c];
}
mh->heap[p] = data;
}
/*
向上调整:
此结点为平衡二叉树的最后结点,除去此结点剩下的堆为最大堆
循环:此结点的值和其父结点比较
大于父节点,父结点覆盖此结点(向下覆盖)
不大于父节点,退出
推出后用被调整的结点替换当前结点
*/
void adjustUp(MaxHeap *mh)
{
int c, data = mh->heap[mh->size];
for(c = mh->size; mh->heap[c/2] < data; c = c/2)
mh->heap[c] = mh->heap[c/2];
mh->heap[c] = data;
}
MaxHeap* create()
{
MaxHeap *mh = new MaxHeap();
int n, i;
cin >> n;
mh->size = n;
for(i = 1; i <= n; i++)
cin >> mh->heap[i];
for(i = n / 2; i > 0; i--)
adjustDown(mh, i);
return mh;
}
/*
插入:
size增加、数据插入,向上调整
*/
void insert(MaxHeap *mh, int x)
{
mh->heap[++mh->size] = x;
adjustUp(mh);
}
/*
返回第一个之后,用最后一个覆盖第一个,size--
向下调整第一个,adjustDown(mh, 1);
*/
int getTop(MaxHeap *mh)
{
int max = mh->heap[1];
mh->heap[1] = mh->heap[mh->size--];
adjustDown(mh, 1);
return max;
}
int main()
{
MaxHeap *mh = create();
for(int i = 1; i <= mh->size; i++)
cout << mh->heap[i] << " ";
cout << endl;
cout << getTop(mh) << endl;
for(int i = 1; i <= mh->size; i++)
cout << mh->heap[i] << " ";
cout << endl;
insert(mh, 10);
for(int i = 1; i <= mh->size; i++)
cout << mh->heap[i] << " ";
return 0;
}