20、画出一个包含N个节点的二叉搜索树的结构草图,该树查找两个最大值需要O(N)的时间。接着,再画出一个包含N个节点的二叉搜索树的结构草图,该树查找两个最大值需要O(1)的时间。
对于需要 O(N) 时间查找两个最大值的二叉搜索树,当所有节点按升序插入时,树会退化为一个长的线性链,类似链表。此时查找最大值需要遍历到链表末尾,查找第二大值需要遍历到倒数第二个节点,时间复杂度为 O(N)。
对于需要 O(1) 时间查找两个最大值的二叉搜索树,树应是高度平衡的,且最大值在根节点的右子节点,第二大值在根节点的右子节点的左子节点,这样可以直接访问到这两个节点,时间复杂度为 O(1)。
由于无法直接绘制草图,可按上述描述自行绘制。
21、如果你想在二叉搜索树中找到第 k 小的键,一种低效的方法是遍历整个树,直到访问了 k 个节点。请在 BinaryTree 中添加一个 select(k) 函数,该函数返回从 0 到 N - 1 的第 k 小的键。为了实现高效的实现,需要扩展 BinaryNode 类,以存储一个额外的字段 N,该字段记录以该节点为根的子树中的节点数(包括该节点本身),例如,叶子节点的 N 值为 1。另外,在 BinaryTree 中添加一个配套方法 rank(key),该方法返回一个从 0 到 N - 1 的整数,该整数反映了键在排序顺序中的排名(即树中严格小于该键的键的数量)。
低效方法是遍历整个树直至访问 k
个节点。高效方法是在 BinaryTree
中添加 select(k)
函数来返回第 k
小的键,同时扩展 BinaryNode
类增加字段 N
记录以该节点为根的子树节点数。此外,在 BinaryTree
中添加 rank(key)
方法,返回键在排序顺序中的排名,即树中严格小于该键的键的数量。
22、AVL树是自平衡的。对于给定的N,由于AVL树无法像完全二叉树那样完美紧凑,能否计算出包含N个值的AVL树的最大高度?生成10000个大小为N的随机AVL树,并记录每个N对应的最大观测高度。创建一个表格,记录最大观测高度增加的情况。预测N的值,使得具有N个节点的AVL树的高度比具有N - 1个节点的AVL树的高度大1。
可以按以下步骤操作:
- 首先,生成 10000 个大小为 N 的随机 AVL 树,记录每个 N 对应的最大观测高度;
- 然后创建表格记录最大观测高度增加的情况;
- 最后根据记录的数据预测满足条件的 N 值。
23、完成一个 SpeakingBinaryTree
类,使其 insert(val)
操作在执行时能生成操作的英文描述。此递归操作是“自上而下”处理的,而大多数递归函数是从基本情况“自下而上”处理的。修改 _insert()
函数以返回一个元组 (node, explanation)
,其中 node
是结果节点, explanation
包含操作的详细描述。
以下是完成后的 SpeakingBinaryTree
类代码:
class BinaryNode:
def __init__(self, val):
self.value = val
self.left = None
self.right = None
class SpeakingBinaryTree:
def __init__(self):
self.root = None
def insert(self, val):
(self.root, explanation) = self._insert(self.root, val, 'To insert `{}`,'.format(val))
return explanation
def _insert(self, node, val, sofar):
if node is None:
explanation = sofar + f' create a new node with value {val}.'
return (BinaryNode(val), exp