算法导论 — 6.1 堆

笔记

本节主要给出(二叉)堆的定义。堆是一种用数组保存的完全二叉树。完全二叉树的意思是,除了树的最底层,其他层都完全充满的。树中的元素按照从上到下、从左到右的顺序保存在数组中。下图给出了堆的一个例子,左图是完全二叉树的形式,右图是堆在数组中的表示。
  在这里插入图片描述
  如果用 A A 表示堆所在的数组,那么 A . l e n g t h A.length 表示数组的容量,即数组最多可容纳的元素的个数; A . h e a p _ s i z e A.heap\_size 表示堆中的元素个数。显然有 A . h e a p _ s i z e A . l e n g t h A.heap\_size ≤ A.length 。树的根结点是元素 A [ 1 ] A[1]
  给定一个结点的下标 i i ,根据下式可以得到它的父结点、左孩子和右孩子的下标:
  在这里插入图片描述
  以上3个公式成立的前提是数组下标从1开始,这是《算法导论》这部书的约定。我们写C/C++代码时,数组下标是从0开始的。在这种情况下,上面3个公式应当变为
  在这里插入图片描述
  二叉堆分两种:最大堆最小堆。在最大堆中,除了根以外的所有结点 i i 都要满足以下性质。即对于任意一棵子树,子树的根结点一定是子树的最大元素。
  在这里插入图片描述
  相反地,在最小堆中,除了根以外的所有结点 i i 都要满足以下性质。即对于任意一棵子树,子树的根结点一定是子树的最小元素。
  在这里插入图片描述

练习

6.1-1 在高度为 h h 的堆中,元素个数最多和最少分别是多少?
  
  高度为 h h 的堆一共有 h + 1 h+1 层。第一层有 1 1 个元素,第二层有 2 2 个元素,第三层有 4 4 个元素,以此类推。除最后一层外,第 i i 层有 2 i 1 2^{i-1} 个元素。
  最后一层为第 h + 1 h+1 层,最少有 1 1 个元素,最多有 2 h 2^h 个元素。因此,高度为 h h 的堆中,最少元素个数为 i = 1 h 2 i 1 + 1 = 2 h \sum_{i=1}^h{2^{i-1}}+1 = 2^h ;而最多元素个数为 i = 1 h + 1 2 i 1 = 2 h + 1 1 \sum_{i=1}^{h+1}2^{i-1} =2^{h+1}-1
  
6.1-2 证明:含 n n 个元素的堆的高度为 l g n ⌊{\rm lg}n⌋
  
  利用练习6.1-1的结论,高度为 h h 的堆中元素最少有 2 h 2^h 个,最多有 2 h + 1 1 2^{h+1}-1 个,即 2 h n 2 h + 1 1 2^h ≤ n ≤ 2^{h+1}-1 。在 n n 的这个取值范围内,必然有 h = l g n h=⌊{\rm lg}n⌋
  
6.1-3 证明:在最大堆的任一子树中,该子树所包含的最大元素在该子树的根结点上。
  

6.1-4 假设一个最大堆的所有元素都不相同,那么该堆的最小元素应该位于哪里?
  
  最小元素可以位于任意一个叶子结点上。

6.1-5 一个已排好序的数组是一个最小堆吗?
  
  如果一个数组已按升序排好序,那么它就是一个最小堆。如果数组按降序排序,那么它是一个最大堆。

6.1-6 值为<23, 17, 14, 6, 13, 10, 1, 5, 7, 12>的数组是一个最大堆吗?
  
  如果画出二叉树,我们会发它并不是一个最大堆。
  在这里插入图片描述

6.1-7 证明:当用数组表示存储 n n 个元素的堆时,叶结点下标分别为 n / 2 + 1 n / 2 + 2 n ⌊n/2⌋+1,⌊n/2⌋+2,…,n
  
  考虑最后一个结点,其下标为 n n ,它的父结点 n / 2 ⌊n/2⌋ 必然是最后一个非叶结点,而之后的结点必然都为叶结点。所以叶结点下标为 n / 2 + 1 n / 2 + 2 n ⌊n/2⌋+1,⌊n/2⌋+2,…,n

猜你喜欢

转载自blog.csdn.net/yangtzhou/article/details/84780286
6.1