Searching
remarks: 从bear导入的,不可见图为草稿,重点部分都有写。
Symbol Tables - 符号表
1. 定义
符号表是一种存储键值对(key value pair)的数据结构
-> dictionary / indices
2. 例子
字典 -> 对应的单词
账户号码 -> 交易详情
3. 符号表的数据结构(implement ST的方式)
3.1 无序链表(LinkedList)
概述:每个节点存储一个键值对
特点:低效
put / get:O(N)
补充:
a) 未命中的查找和插入操作都需要N次比较,命中的查找在最坏的情况下需要N次比较(如果需查找的在最后一个)。
b) 向一个空表中插入N个不同的键,需要~N^2/2次比较。
3.2 有序数组(二分查找法)
概述:使用一对平行的数组,一个存储键一个存储值
特点:比无序链表好
get / contains / floor / ceiling / rank:O(logN)
补充:
a) 在N个键的有序数组中进行二分查找最多需要lgN+1次比较(无论是否成功)。
b) 向一个大小为N的有序数组中插入一个新元素,在最坏的情况下需要访问2N次数组(因为是平行数组),因此向一个空符号表中插入N个元素,在最坏情况下需要访问N^2次数组。
4. 总结
[image:7C736441-D34E-41B1-9FA4-5A1D4D3995A0-9185-000007FCA9424E7B/24905163-3cea210e5187377e.jpg]
[image:61547CCE-46E1-4631-AAB5-3C0FF9186913-9185-000007FCB1D6698D/24905163-be9a5190830cfbe5.jpg]
[image:5B82409C-1FFC-4623-AFDD-3DE8365425C0-9185-0000080129C080A6/Photo Nov 14, 2020 at 110915 AM.jpg]
Hashtables
步骤:1. 散列表函数;2. 处理碰撞冲突
1. 引入原因
可以快速访问任意键的值;可实现在一般应用中拥有常数级别的查找和插入操作的符号表,因此它在很多情况下成为实现简单符号表的最佳选择。
但hashtable是unordered的
Remarks:
M: size of the table
N: the numb of pairs
2. 基于拉链法的散列表(zig-zag)
2.1 特点
a) 用M条链表保存N个键,无论键在各个链表中如何分布,链表的平均长度肯定是N/M
b) 在一张含有M条链表和N个键的散列表中,任意一条链表中的数量均在N/M的常数因子范围内的概率无限趋近于1
c) 在一张含有M条链表和N个键的列表中,未命中查找和插入操作所需的比较次数为~N/M
3. 基于线性探测法的散列表(linear-probing)
3.1 特点
当碰撞发生时,直接检查散列表的下一个位置
3.2 键簇的问题
a) linear probing的平均成本取决于元素在插入数组后聚集成的一组连续的条目(键簇)
b) 很短的键簇才能保证效率
c) 长键簇更长的可能性比短键簇更大
3.3 数组大小的问题
保证效率,需保证散列表的使用率永远不会超过1/2
3.4 均摊分析(没懂)
假设一张散列表能够自己调整数组的大小,初始为空,执行任意顺序的t次查找、插入和删除操作所需的时间和t成正比,所使用的内存量总是在表中的键的总数的常数因子范围内
4. Separate Chaining
4.1 特点
hash table is an array of LinkedList
处理冲突的方式就是把item加入LinkedList里
worst case: O(N)
best case: O(N/M)
5. Quadratic Probing
h(k), h(k)+1^2, h(k)+2^2, h(k)+3^2 ...
4. 总结
4.1 内存使用
[image:F5127531-A33D-4D9F-8720-1786F994E34F-9185-000007FCBBB38E4A/24905163-63d9a22f7f554d95.jpg]
- hashtable的表现是取决于hash function的
- insert和find的平均runtime是常数
4.2 缺点
- 需要一个优秀的hashCode
- 性能保证来自于hashCode的质量
- hashCode的计算可能复杂且昂贵
- 难以支持有序性相关的符号表操作(cannot sort)
5. HashCode
hashCode(k)永远返回相同的值,只要k不变
Modular hashing: key / size
Binary Search Trees - 二叉查找树
1. 定义
BST是一颗二叉树,其中每个节点都含有一个Comparable的键以及相关联的值,且每个节点的键都大于其左子树中的任意节点的键,且小于右子树的任意节点的键
2. 引入原因
BST能够将LinkedList插入的灵活性和有序数组(ordered array)查找的高效性结合起来(但在最坏情况下,性能取决于树的高度)
3. BST的数据结构
a) 在由N个随机键构造的二叉查找树中,查找命中平均所需的比较次数为~2lnN=1.39lgN
b) 在由N个随机键构造的二叉查找树中,插入操作和查找未命中平均所需的比较次数为~2lnN=1.39lgN
c) 在一棵二叉查找树中,所有操作在最坏情况下所需的时间和树的高度成正比
4. Best case & Worst case
在BST里,
Best case: 完全平衡树(perfect balanced tree) -> O(logN)
Worst case: 一条线(相当于linear search) -> O(n)
5. 总结
[image:029AB6EE-8AC9-47D9-9400-51E5907E1E91-9185-000007FCC907A508/24905163-46741d12f660af27.jpg]
BST的pros
- 实现方式简单
- 平均成本很优秀
BST的cons
- worst case的时间复杂度不好(因为会成一条线,导致时间复杂度为O(N))
Remarks: 因此有了2-3树和红黑树
6. BST的删除
如果删除的node有left node & right node,那么用right node的left node替代要删除的node
Balanced Search Tree
引入原因:其他算法在最坏情况下都是N(尤其是BST),但以下两种可以保证无论如何构造,运行时间都是对数级别的。
2-3 tree
1. 定义
一棵2-3查找树由2-节点和3-节点组成
2-节点(和正常树相同):左
3-节点:左
log_3N <= height <= log_2N
big-O: O(logN)
2. 2-3树的数据结构
在一棵大小为N的2-3树中,查找和插入操作访问的节点必然不超过lgN个
3. put的总结
[image:409AD33A-B763-4996-BCB8-2CDCE0271F6B-9185-0000081F72C20F8E/Photo Nov 14, 2020 at 123935 PM.jpg]
4. 2-3 tree的总结
Pros:
- 可以保证最坏情况下的时间复杂度
Cons: - 不是正常的树,因为包含两种nodes(2和3)
- 难以实现
- 实现起来可能比常规BST的开销更大
red-black tree
1. 定义
a) 红链接均为左链接
b) 没有任何一个结点同时和两条红链接相连
c) 该树是完美黑色平衡的,即任意空链接到根节点的路径上的黑链接数量相同
2. 规则
- a black node has at most 1 red child
- red nodes have black children
- the root is always black
- tree has perfect black balance
3. 旋转机制
出现红色右链接,需要左旋转
[image:1D550122-BDD2-46E7-9177-81B9918CB8CE-9185-00000828F15BBC81/[email protected]]
[image:E72D6947-DA2D-4835-B8BC-FAB8838449DE-9185-0000082AC948A866/[email protected]]
[image:A0C5CC13-5C49-45AA-835E-7C4CC4C991FC-9185-0000082B7794806E/[email protected]]
[image:0B92178D-6C43-4AE7-A549-7016A773F8F2-9185-00000831BAFD5F01/[email protected]]
4. 红黑树的性质
a) 所有基于红黑树的符号表实现都能保证操作的运行时间为对数级别
b) 一棵大小为N的红黑树的高度不会超过2lgN
c) 一棵大小为N的红黑树中,根节点到任意节点的平均路径长度为~1.00lgN
d) 在一棵红黑树中,以下操作在最坏情况下所需的时间是对数级别的:get(), put(), 查找最大/最小键, floor(), ceiling(), rank(), select(), deleteMin(), deleteMax(), delete(), range()
5. 总结
[image:4AEF4128-09E8-485D-91A8-7318F2A13E7D-9185-000007FCDB340932/24905163-6ed470a0a3839a76.jpg]
Skip lists(slides上有searching的总结)
1. 概念
跳跃列表,允许快速查询;查找从底部最稀疏的子序列向下进行,直至需要查找的元素在该层两个相邻的元素中间。
2. 由来
- 提高单链表的效率,单链表的效率是O(N)
- 达到效率高和简单实现的平衡
3. 跳表的数据结构
查询、插入、删除:(大概率,但不保证是)O(logN)
特殊情况:如果所有node全在level0, 那么Skip list就相当于Linkedlist,因此,在那个情况下insert / search的效率为O(N)
Cons:需要更多空间, O(N) <- 这一点上不如BST
AVL trees
1. 概述
左子树和右子树的高度差不超过1
-> height(left subtree) - height(right subtree) = {-1, 0, 1}
pivot: 不平衡树的根
2. single rotation
插入的node在左子树 -> SR to right
插入的node在右子树 -> SR to left
[image:342806BD-E5BC-4404-9B19-D760BB88546A-9185-00000842782481CF/[email protected]]
3. double rotation
左右高度差值为2
[image:04E249B3-ECB6-4FD2-9DFB-5603C3C899F2-9185-000008434E8C262C/[email protected]]
4. 总结
height不超过O(logN)
put / get / delete: 取决于height -> 时间复杂度是O(logN)
Splay Trees
1. 由来
80%搜索的东西只占20%的内存
=搜索谁就把谁提到root上去
2. 时间复杂度
- 不能保证balance,因此worst case是O(N)
- 但search&insert的amortized cost是O(logN)
Reference
十分钟弄懂什么是跳表,不懂可以来打我
数据结构与算法——跳表