東京大学 新領域創成科学研究科 メディカル情報生命専攻 2014年8月実施 問題9
Author
zephyr
Description
An array of n real numbers, H[1,…,n], is called a heap if H[⌊i/2⌋]≥H[i] for 1<i≤n, where ⌊i/2⌋ is the quotient of integer i divided by 2 (e.g., ⌊4/2⌋=⌊5/2⌋=2). A heap can be treated as a binary tree such that H[1] is the root node and H[⌊i/2⌋] is the parent node of H[i]. Answer the following questions.
(1) Explain whether array [6,3,4,1,0,3,4,2] is a heap or not.
(2) Show that if H[1,…,n] is a heap, H[1,…,j] is also a heap for any j (1≤j<n).
(3) Suppose that H[1,…,n] is a heap but H[1,…,n+1] is not. Describe a procedure that exchanges elements in H[1,…,n+1] to make it a heap in O(logn) worst-case time.
(4) Suppose that H[1,…,n] is a heap. Prove that H[1] is maximum among all elements in H[1,…,n]. Suppose that after replacing H[1] with H[n], H[1,…,n−1] is not a heap. Describe a procedure that exchanges elements in H[1,…,n−1] to make it a heap in O(logn) worst-case time.
(5) Describe an algorithm that exchanges elements in H[1,…,n] to make it a heap in O(n) worst-case time.
(6) Using the procedures defined above, describe an algorithm that sorts array H[1,…,n] in O(nlogn) worst-case time.
一个包含 n 个实数的数组 H[1,…,n],如果满足 H[⌊i/2⌋]≥H[i] 对于 1<i≤n,其中 ⌊i/2⌋ 是整数 i 除以 2 的商(例如,⌊4/2⌋=⌊5/2⌋=2),则称其为堆。堆可以被看作是一个二叉树,其中 H[1] 是根节点,H[⌊i/2⌋] 是 H[i] 的父节点。回答以下问题。
(1) 解释数组 [6,3,4,1,0,3,4,2] 是否是一个堆。
(2) 证明如果 H[1,…,n] 是一个堆,那么 H[1,…,j] 也是一个堆,对于任何 j (1≤j<n)。
(3) 假设 H[1,…,n] 是一个堆,但 H[1,…,n+1] 不是。描述一种在 O(logn) 最坏情况下,将 H[1,…,n+1] 中的元素交换使其成为堆的方法。
(4) 假设 H[1,…,n] 是一个堆。证明 H[1] 是 H[1,…,n] 中最大的元素。假设在用 H[n] 替换 H[1] 后,H[1,…,n−1] 不是一个堆。描述一种在 O(logn) 最坏情况下,将 H[1,…,n−1] 中的元素交换使其成为堆的方法。
(5) 描述一种在 O(n) 最坏情况下,将 H[1,…,n] 中的元素交换使其成为堆的算法。
(6) 使用上述定义的方法,描述一种在 O(nlogn) 最坏情况下,对数组 H[1,…,n] 进行排序的算法。
题目描述
对含 n 个实数的数组 H[1,…,n],若
H[⌊i/2⌋]≥H[i](1<i≤n),
则称其为堆;这里 ⌊i/2⌋ 是 i 除以 2 的整数商。在对应二叉树中,H[1] 为根,H[⌊i/2⌋] 为 H[i] 的父节点。回答下列问题:
- 判断数组 [6,3,4,1,0,3,4,2] 是否为堆并说明理由。
- 证明若 H[1,…,n] 为堆,则任意前缀 H[1,…,j](1≤j<n)也为堆。
- 若 H[1,…,n] 是堆而加入 H[n+1] 后不再是堆,描述仅通过交换元素、在最坏 O(logn) 时间内恢复 H[1,…,n+1] 堆性质的过程。
- 证明堆顶 H[1] 是 H[1,…,n] 的最大元素;再设以 H[n] 替换 H[1] 后 H[1,…,n−1] 不再为堆,描述最坏 O(logn) 时间的交换恢复过程。
- 描述通过交换元素在最坏 O(n) 时间内把任意 H[1,…,n] 建成堆的算法。
- 利用上述过程,描述最坏时间为 O(nlogn) 的数组排序算法。
- 堆性质与堆调整:依据父节点不小于子节点的条件验证堆,并分别设计插入后的上浮与删除堆顶后的下沉过程。
- 线性时间建堆:从内部节点自底向上调整,说明整体建堆为何可在最坏 O(n) 时间完成。
- 堆排序:反复把最大堆的堆顶移至未排序区末端并恢复堆,论证最坏 O(nlogn) 的运行时间。
Kai
(1)
To determine if the given array is a heap, we need to check if for every i>1, the condition H[⌊i/2⌋]≥H[i] holds.
- i=2: ⌊2/2⌋=1⇒H[1]=6≥H[2]=3
- i=3: ⌊3/2⌋=1⇒H[1]=6≥H[3]=4
- i=4: ⌊4/2⌋=2⇒H[2]=3≥H[4]=1
- i=5: ⌊5/2⌋=2⇒H[2]=3≥H[5]=0
- i=6: ⌊6/2⌋=3⇒H[3]=4≥H[6]=3
- i=7: ⌊7/2⌋=3⇒H[3]=4≥H[7]=4
- i=8: ⌊8/2⌋=4⇒H[4]=1<H[8]=2
Since H[4]=1 is not greater than or equal to H[8]=2, the array [6,3,4,1,0,3,4,2] is not a heap.
(2)
Statement: If H[1,…,n] is a heap, then H[1,…,j] is also a heap for any j (1≤j<n).
Proof:
Let H[1,…,n] be a heap, meaning H[⌊i/2⌋]≥H[i] for all 1<i≤n. Consider any j<n. Since the heap property holds for all elements in H[1,…,n], it will also hold for all elements in H[1,…,j] because the parent-child relationships in the heap are preserved up to index j. Therefore, H[1,…,j] is also a heap.
(3)
Suppose H[1,…,n] is a heap, but after inserting an element at position n+1, the array H[1,…,n+1] is not a heap. The violation of the heap property could only occur if the newly inserted element at position n+1 is greater than its parent. To fix this, we perform the heapify-up operation.
Heapify-up Procedure:
- Let i=n+1.
- While i>1 and H[i]>H[⌊i/2⌋]:
- Swap H[i] and H[⌊i/2⌋].
- Set i=⌊i/2⌋.
Time Complexity: The worst-case time complexity of this procedure is O(logn), as we may need to traverse up the height of the heap, which is logarithmic in terms of the number of elements.
(4)
Proof that H[1] is the maximum element in H[1,…,n]:
By the definition of a max-heap, the root node (i.e., H[1]) must be greater than or equal to all its children. By induction, it can be proven that H[1] is greater than or equal to all elements in the heap. Hence, H[1] is the maximum element.
Heapify-down Procedure:
After replacing H[1] with H[n], if H[1,…,n−1] is not a heap, we need to restore the heap property by performing the heapify-down operation.
- Let i=1.
- While 2i≤n−1 (i.e., while i has at least one child):
- Let j=2i (left child).
- If j<n−1 and H[j+1]>H[j], set j=j+1 (right child is larger).
- If H[i]≥H[j], break the loop.
- Swap H[i] and H[j].
- Set i=j.
Time Complexity: The worst-case time complexity of this procedure is O(logn), as we may need to traverse down the height of the heap.
(5)
To convert an unordered array H[1,…,n] into a heap, we can use the build-heap algorithm:
Build-Heap Algorithm:
- Start from the last non-leaf node, ⌊n/2⌋.
- Perform heapify-down on each node from ⌊n/2⌋ to 1.
Time Complexity: The build-heap process has a time complexity of O(n), as it performs a linear number of operations over the array.
(6)
Using the above procedures, we can describe the Heapsort algorithm:
- Build-Heap: Convert the array H[1,…,n] into a max-heap.
- Extract-Max repeatedly: Swap H[1] with H[n], reduce the size of the heap by 1, and then perform heapify-down on H[1,…,n−1].
- Repeat the above step until the heap size is reduced to 1.
Time Complexity: The time complexity of Heapsort is O(nlogn) because:
- Building the heap takes O(n) time.
- Each extraction and heapify-down takes O(logn) time, and there are n such extractions.
Knowledge
堆 堆排序 复杂度分析
解题技巧和信息
堆问题的核心是维护堆的性质,通过理解堆的定义(最大堆或最小堆)来选择合适的操作(如 heapify-up 或 heapify-down)。在建堆和堆排序时,关注堆的高度和操作的时间复杂度。堆操作通常具有 O(logn) 的时间复杂度,而建堆的复杂度为 O(n)。
重点词汇
- heap 堆
- heapify 堆化
- max-heap 最大堆
- build-heap 建堆
- heapify-down 下滤
- heapify-up 上滤
参考资料
- Introduction to Algorithms, 3rd Edition, Chapter 6: Heapsort
- Data Structures and Algorithm Analysis in C, Chapter 7: Heaps