堆是一个完全二叉树,对于堆的所有非叶子节点,其左右子树都比该节点大(/小)。
完全二叉树的性质:
- 左儿子节点:2 * x
- 右儿子节点:2 * x + 1
手写堆的话一般可以用一个一维数组去模拟。堆的基本操作有两个,其他操作都可以由这两个操作排列组合得到:
up
:将一个节点往上push,若该节点比其父亲节点的值大(/小),则将该节点和父亲节点交换。down
: 将节点往下down,看该节点和左右两个儿子谁的值大(/小),最大(/小)的和父亲节点交换。
对于STL中的优先队列,其一般实现的操作有以下三个:
push
: 往堆中插入一个元素, heap[++sz] = x; up(sz);
top
: 取堆顶元素,heap[1]
pop
: 弹出堆顶元素,heap[1] = heap[sz]; sz--; down(1);
具体可参考如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| #include <iostream>
using namespace std;
const int MAXN = 1e5+7; int heap[MAXN], sz = 0;
void up(int u) { while (u / 2 && heap[u] < heap[u / 2] ) { swap(heap[u], heap[u / 2]); u = u / 2; } }
void down(int u) { int tmp = u; if (u * 2 <= sz && heap[u * 2] < heap[tmp]) tmp = u * 2; if (u * 2 + 1 <= sz && heap[u * 2 + 1] < heap[tmp]) tmp = u * 2 + 1; if (u != tmp) { swap(heap[u], heap[tmp]); down(tmp); } }
void push(int n) { heap[++sz] = n; up(sz); }
int top() { if (sz >= 1) return heap[1]; return -1; }
void pop() { if (sz == 0) return; heap[1] = heap[sz]; sz--; down(1); }
int main() { char opt[5]; printf(">"); while(scanf("%s", opt) != EOF) { if (opt[1] == 'u') { int n; scanf ("%d", &n); push(n); } else if (opt[0] == 't') { printf ("top: %d\n", top()); } else if (opt[0] == 'p') { if (top() == -1) { printf ("heap empty!\n>"); continue; } printf ("%d pop success\n", top()); pop(); } else { printf ("input error, command push, pop, top\n"); } printf(">"); } }
|