1 一个数组,始终保持最大/最小的元素在a[0]单元,该数组可以追加元素,可以随时取走a[0]这个最大/最小元素.
2 解决思路:保证数组a[0]始终存放最大/最小元素,且数组整体分布特征满足一定条件,使得在数组元素发生变化时,在最少的时间内使得a[0]仍是最大/最小元素.
3 牵扯3个问题:
4 (1) 给一个随机分布的无序数组,怎样把数组元素的位置调整成a[0]是最大元素,且初始化好数组元素分布特征.
5 (2) 追加一个元素,扔保证a[0]最大/最小,且分布特征不变
6 (3) 取走a[0],补充a[0]仍使a[0]最大/最小,且分布特征不变.
7 如果不维持数组元素的分布特征,每次数组动态变化,保持a[0]最大/最小,时间复杂度都是O(n).如果维持数组元素的分布特征,使得除了第一次初始化数组元素分布特征,时间复杂度是O(n),以后每次保持a[0]最大/最小,时间复杂度都是O(logn).
8 解决方案:
9 把数组映射成一棵完全二叉树,a[0]就是根节点,使得每个结点满足条件:以该结点为根的二叉树,左子树和右子树的所有结点都 <= 或 >= 根结点.
10 堆的特点
11 以根为基准把树劈成两半,左子树和右子树结点的大小没有必然关系。
12 建堆复杂度O(n)
13 (1)downAdjust函数: downAdjust(Type array,int i);假设a[i]结点的左子树右子树都是最堆,a[i]与左孩子右孩子关系还未调整,该函数就是调节a[i].
14 从完全二叉树最后一个有孩子结点的结点开始逆序往上一直到根结点,对每个结点执行downAdust,便成了堆.
15 插入O(logn)
16 插入就是追加到数组尾,即完全二叉树最底层增加一个结点,然后执行一次upAdjust函数即可.
17 删除O(logn)
18 删除就是取走a[0],从剩下元素拿来一个补充. 把完全二叉树最后一个结点放到a[0],数组元素个数减1.对a[0]执行downAdjust.
19 /*实现一个最大堆*/
20 #include<stdio.h>
21 #include<stdlib.h>
22
23 /*交换*/
24 void swap(int *a, int *b) {
25 int temp;
26 temp = *a;
27 *a = *b;
28 *b = temp;
29 }
30
31 /*向下调整*/
32 void downAdjust(int *a,unsigned i,unsigned length) {
33 unsigned max;
34 unsigned halfNum = length >> 1;
35 while (i <= halfNum) {
36 if (2 * i + 1 <= length)
37 max = a[2 * i] > a[2 * i + 1] ? 2 * i : 2 * i + 1;
38 else
39 max = 2 * i;
40
41 if (a[i] < a[max]) {
42 swap(&a[i], &a[max]);
43 i = max;
44 }
45 else
46 return;
47 }
48 }
49
50 /*建堆*/
51 void buildHeap(int *a, unsigned int length) {
52 for (int i = length >> 1; i >= 1; --i) {
53 downAdjust(a, i, length);
54 }
55 }
56 /*追加调整*/
57 void addAdjust(int *a, unsigned int length,int value) {
58
59 }
60 /*删除调整*/
61 void deleteAdjust(int *a, unsigned int length) {
62
63 }
64 int main() {
65 int a[11] = { 10,1, 8, 7, 0, 19, 5, 2, 23, 4, 6 };
66 buildHeap(a, 10);
67 for (int i = 1; i <= 10; ++i) {
68 printf("%d ", a[i]);
69 }
70 system("pause");
71 return 0;
72 }