Searching简述

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 缺点

  1. 需要一个优秀的hashCode
  2. 性能保证来自于hashCode的质量
  3. hashCode的计算可能复杂且昂贵
  4. 难以支持有序性相关的符号表操作(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-节点(和正常树相同):左node
3-节点:左node1 && 右>node2
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. 由来

  1. 提高单链表的效率,单链表的效率是O(N)
  2. 达到效率高和简单实现的平衡

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

十分钟弄懂什么是跳表,不懂可以来打我
数据结构与算法——跳表

你可能感兴趣的:(Searching简述)