Data Structure II
1. ADT地图
get(k): | 如果映射M有一个键为k的条目,返回它的相关值 |
put(k, v): | 如果key k不在M中,那么插入(k, v)到映射M中;否则,用v替换与k相关的现有值 |
remove(k): | 如果地图M有一个键为k的条目,移除它 |
entrySet(): | 返回M中条目的可迭代集合 |
keySet(): | 返回一个可迭代的M中键的集合 |
values(): | 返回M中值的可迭代集合 |
size(),isEmpty () |
2. 二叉搜索树 Binary Search Trees (BST)
二叉搜索树是存储满足以下BST属性的键(或键-值对)的二叉树
对于树中的任意节点v, v左子树中的任意节点u, v右子树中的任意节点w,
key(u) < key(v) < key(w)
注意,二叉搜索树的顺序遍历是按递增顺序访问键的。
用二叉搜索树进行搜索
为了搜索关键字k,我们从根结点开始沿着一条向下的路径
为了决定是向左还是向右,我们将当前节点v的键值与k进行比较
如果我们到达一个外部节点,这意味着键不在数据结构中
运行时间为O(h),其中h是树的高度
最坏情况是h = n
最好的情况是h = log2n
2.1 插入
为了执行操作put(k, o),我们搜索关键字k(使用search)
如果在树中找到k,用o替换对应的值
如果没有找到k,设w为搜索到的外部节点。我们用一个保持(k, o)的内部节点替换w
例子:insert 23
2.2 删除
为了执行remove(k)操作,我们搜索键k(使用搜索),以找到持有k的节点w
我们区分两种情况:
- w有一个外部子结点
- w有两个内部子结点
w有一个外部子结点
假设我们想要移除的节点w有一个外部子节点,我们称之为z。
为了移走w:
- 从树中移除w和z
- 提升w的另一个孩子取代w的位置
w有两个内部子结点
假设我们想要移除的节点w有两个内部子节点。
为了移走w:
- 在有序遍历中找到w后面的内部节点y(即,y在w下的右子树中具有最小的键值)
- 我们将该项从y复制到节点w中
- 我们删除节点y和它的左子节点z,它必须是外部的,使用前面的情况
2.3 复杂性
考虑一个由高度为h的二叉搜索树实现的有n个项的映射:
- 使用的空间是O(n)
- 取、放、移取时间为O(h)
高度h在最坏情况下可以是n,最好情况下是log n。
因此,我们能期望的最好结果是树操作需要O(log n)时间,但通常我们只能保证O(n)。但前者可以通过更好的插入例程来实现。
2.4 保持平衡的BST
我们已经看到运行BSTs的操作需要O(height)时间。不幸的是,标准插入实现可能导致树的高度为n-1(例如,如果我们按照排序的顺序插入)。在今天余下的课程中,我们将讨论更复杂的算法,这些算法通过简单的局部变换来重新平衡树,从而始终保持高度为O(log n)的BST。
改善平衡:Trinode重组
设x, y, z为结点,使x是y的子结点,y也是z的子结点。
设a b c是x y z的顺序列表
执行旋转,使b成为三个节点中最上面的节点。
3. 秩平衡树 rank-balance tree
3.1 AVL树
定义
AVL树是秩平衡树,其中r(v)是其根为v的子树的高度
平衡约束:每个内部节点的两个子树的秩最多相差1。
存储n个键的AVL树的高度是O(log n)
性质
假设我们有一个存储n个元素的AVL树
-数据结构使用O(n)空间
-树的高度O(log n)
-搜索花费O(log n)时间
-插入花费O(log n)时间
-移除花费O(log n)时间
4. 优先队列ADT
特殊类型的ADT映射存储键值项的集合,其中我们只能删除最小的键:
- insert(k,v): 插入键k和值v
- remove_min():删除并返回键值最小的项
- min():返回具有最小键值的项
- size():返回存储了多少项
- is_empty():测试队列是否为空
4.1 基于优先级队列
未排序的列表实现
- insert在O(1)时间,因为我们可以在序列的开始或结束插入项
- remove_min和min需要O(n)时间,因为我们必须遍历整个列表以找到最小的键
排序的列表实现
- insert在O(n)时间内,因为我们必须找到插入项的位置
- remove_min和min在O(1)时间,因为最小的键在开始
4.2 优先队列排序
我们可以使用优先队列排序键列表:
- 迭代地将键插入空的优先队列
- 迭代地remove_min以排序的顺序获取键
复杂性分析:
- n次插入操作
- n个remove_min操作
基于序列的实现采取O(n^2)
4.3 选择排序
pq-sort的变体使用未排序序列实现:
- 用n个插入操作插入元素需要O(n)时间
- 用n个remove_min操作删除元素需要O(n2)
可以就地完成(不需要额外空间)
顶层循环不变式:
- A (0, i)是有序的
- A[i, n]是优先队列
4.4 插入排序
pq-sort的变体使用排序序列实现:
- 通过n次插入操作插入元素需要O(n2)时间
- 使用n个remove_min操作删除元素需要O(n)
可以就地完成(不需要额外空间)
顶层循环不变式:
- A[0, i]是优先队列(因此排序)
- A[i, n]是剩下的
5. 堆数据结构 heap data strycture
堆是一棵在节点上存储(键、值)项的二叉树,满足以下属性:
- 堆序:对于每个m≠根节点,Key(m)>=key(parent(m))
- 完全二叉树:设h为高度
- 每一级i < h都满了(即有2i节点)
- 剩余节点位于h级最左侧位置
根始终持有堆中最小的键
存储n个键的堆高度为log n
5.1 插入到堆中
-用给定的密钥创建一个新节点
-找到新节点的位置
-恢复堆序属性
Upheap
通过从插入点开始沿向上路径交换键来恢复堆序属性
正确性:交换后以z为根的子树具有该属性
复杂度:O(log n)时间,因为堆的高度是log n
5.2 从堆中移除
-用最后一个节点w的键替换根键
-删除w
-恢复堆序属性
downheap