-
主要要解决的问题( O(logn) ):
- insert
- extract_min
-
1.二叉树的形式呈现
-
条件:
- Heap Property:子节点大于父节点
- Shape property:每一层一定是从左到右
-
insert(假设最开始是这样的)
1 5 2 6 8 7 4 10
- 这时候假设要插入3,那首先位置一定是在10右边,然后再看条件Heap Property,那那么只需要跟父节点比就行,到比父节点大就行了
- 最坏的结果也就是 O(logn)
-
考虑树的h(高度)与n(总节点个数)
1 + 2 + 2^2 + ... + 2^(h-2) < n <= 1 + 2 + 2^2 + ... + 2^(h-1) ---------> 2^(h-1)-1 < n <= 2^(h)-1 ---------> h < log(n+1)+1 <= h+1
-
extract_min
- 1.把根结点取出后,用最右下角的的结点放到根结点
- 2.跟两个子结点中较小的一个交换,直到两个子结点比它大或者或者为空
- 最坏的结果也就是 O(logn)
-
-
1.数组的形式呈现
-
1.假设最开始堆是这样的:
2 3 4 5 8 7 6 10 9
-
2.那么在数组中应该是这样存储的:
index 1 2 3 4 5 6 7 8 9 value 2 3 4 5 8 7 6 10 9
-
3.以extract_min为例,第一步交换到根结点:
index 1 2 3 4 5 6 7 8 9 value 9 3 4 5 8 7 6 10 -
-
4.第一次交换后为:
index 1 2 3 4 5 6 7 8 9 value 3 9 4 5 8 7 6 10 -
-
5.第二次交换后为:
index 1 2 3 4 5 6 7 8 9 value 3 5 4 9 8 7 6 10 -
-
6.再来回顾交换的过程:
- A[1]与min(A[2],A[3])交换,A[2]与min(A[4],A[5])交换,很明显可以看到我们可以在constant time内找到应该比较的两个下标,并且交换的次数最多也只是log(n)
- insert过程差不过,假设我们要插入结点的index是k,那么我们也很容易在constant time内找到父结点的index=k/2
-
7.堆排序
-
1.就是n词call insert,n次call extract_min,那么按理说时间复杂度就是
O(2*n*logn)
-
2.其实insert可以优化成O(n),做法很简单,就最开始全部随便填进array
1 4 5 8 3 2 9 7 6
- 从最下层往上(从右往左)交换就行了,8跟6换,5跟2换,3跟4换
-
复杂度O(n)的证明:
2^h 2^h 2^h 2^h ---(个结点)*0(次交换)+----x1 + ---x2 + ... + ---*(h-1) 2 4 8 2^h -------------------> 2^(h-2)x1 + 2^(h-3)x2 + 2^(h-4)x3 + ... + 1x(h-1) ------------------- 因为:1+c+c^2+c^3+...=1/(1-c) 求导:1+2c+3c^2+3c^2+...=1/(1-c)^2 ------------------- 对比上式,把2^(h-2)提出来,容易计算出<2^(h-2)*4=2^h=n
-
-