原地算法
6.1 堆
二叉堆:存储上使用数组,逻辑上是二叉树,近似于完全二叉树。
存储顺序是树的广度优先遍历顺序。
第i个节点的父节点存储在 ⌊i/2⌋ 中。(数学归纳法可证)
第i个节点的左孩子存储在 2i 中。
第i个节点的父节点存储在 2i+1 中。
最大堆性质:父节点元素大于等于子节点元素。(根节点除外,其没有父节点)
最大堆性质:父节点元素小于等于子节点元素。(根节点除外,其没有父节点)
节点的高度:该结点到叶结点最长简单路径上边的数目。
堆的高度就是根结点的高度。
n个结点的完全二叉树的高度是$\Theta(lgn)$
练习:
等比数列求和公式:
6.1-1 最少:
最多:
6.1-2 设 n=2h+k,0≤k≤2h−1,k∈Z 易得。
6.1-6 不是,7的位置有问题。
6.1-7 完全二叉树中叶结点的数目为 ⌈n2⌉
推导如下:
设叶子节点个数为n0,度为1的节点个数为n1,度为2的节点个数为n2。
1. n0+n1+n2=n
2. 1+n1+2*n2=n
消去n2,得:
n0=(n+1-n1)/2
由完全二叉树性质得,n1为1或者0.若树高为h,则除最下层结点外,结点总数为$2^h-1$
,为奇数。
故n为奇数时,n1为0
n0=(n+1)/2故n为偶数时,n1为1
n0=n/2
由此,完全二叉树中叶结点的数目为 ⌈n2⌉
由叶结点下标计算完全二叉树中叶结点的数目:
得证。
6.2 维护堆的性质
每个孩子的子树至多为
2n/3
。
最坏情况分析。
设矮的子树高为h,高子树为h+1。
矮子树结点数
2h−1
,高子树节点数
2h+1−1
,又
n=2h+1−1+2h−1
,故可认为高子树结点数为
2n/3
练习
6.2-4 注意完全二叉树的性质,这个结点应该是叶子结点。
6.3 建堆
注意这个算法实际上是线性时间的。
练习
6.3-3 对高度为0或者h的结论易证,一般情况数学归纳法可证。
6.4 堆排序算法
排序完成是升序。
练习
6.4-4 升序在建堆的过程中会破坏这个序,故其需要 O(n)+(n−1)lgn ;降序本身能看成是一个最大堆,maxHeapify不会发生递归,则 O(n) 。
6.5 优先队列
示例是最大优先队列。
支持操作:
- 插入
- 返回最大值(heapMax)
- 返回最大值并将其从堆中移除(heapExtractMax)
- 将元素x的关键字增加到k(heapIncreaseKey),维持堆的性质,也就是下层结点值会变大。
练习
6.5-8 把这个数和数组尾部的数互换,调整这个子树
6.5-9
1. 从k个链表中取出每个链表的第一个元素,组成一个大小为k的数组arr,然后将数组arr转换为最小堆,那么arr[0]就为最小元素了
2. 取出arr[0],将其放到新的链表中,然后将arr[0]元素在原链表中的下一个元素补到arr[0]处,即arr[0].next,如果 arr[0].next为空,即它所在的链表的元素已经取完了,那么将堆的最后一个元素补到arr[0]处,堆的大小自动减一,循环n-k次即可。
思考题
6-3 young氏矩阵
这个形式的矩阵似乎在校招笔试中出现多次。