普林斯顿算法4-Ch3 查找

Finding The Essence of your life

Posted by R1NG on September 25, 2021 Viewed Times

Ch3 查找

在本章中, 我们将对一系列 经过实践检验的 经典查找算法进行介绍和讨论. 我们会使用 符号表 描述一张 抽象 的表格, 并假定会将 信息 (值) 存储于其中, 按照指定的 检索这些信息. 的具体意义取决于不同的实际应用.

符号表 往往又被称为 字典. 类比于英语字典, 就是 单词, 就是该单词对应的 定义, 发音和词源等解释. 符号表也可以被称为 索引. 在一本书的索引中, 就是 术语, 而 就是 书中该术语出现的所有位置.

在说明基本的 API 和两种实现后, 我们会使用三种数据结构: 二叉查找树, 红黑树, 散列表 对符号表进行高效的实现.

3.1 符号表

符号表的主要作用是 将一个键和一个值相关联. 要实现符号表, 首先需要定义其背后的数据结构, 并指明创建并操作这种数据结构, 以实现插入, 查找等操作所需的算法.

定义

符号表 是一种 存储键值对 的数据结构, 支持两种操作: 插入 (将一对新的键值对存入表中) 和 查找 (根据给定的键得到相应的值).

API

显然, 符号表也是一种典型的 抽象数据类型. 其 API 如下:

public class ST<Key, Value>  
  ST() 创建符号表
void put(Key key, Value, val) 将键值对存入表中, 若值为空则将键 key 从表中删除
Value get(Key key) 获取键 key 对应的值, 若键不存在则返回 null
void delete(Key key) 从表中删去键 key 及其对应的值
boolean contains(Key key) 检查键 key 在表中是否有对应的值
boolean isEmpty() 检查表是否为空
int size() 返回表中键值对的数量
Iterable<Key> keys() 返回表中所有键的集合

我们下面再解释一些具体实现中的一些设计规则.

1. 泛型

和排序一样, 在设计方法时, 我们不指定处理对象的类型. 我们通过 明确指定查找时键和值的类型 区分它们.

2. 键重复的情形

在所有实现中我们都遵循下列规则:

  1. 键值一一对应.
  2. 当将要存入的键值对和表中已有的键 (及其关联的值) 相冲突时, 用新值替换旧的.

3. 空键和空值

我们的实现中不允许空键和空值.

4. 删除操作

在符号表中, 删除的实现可以是 延时删除 (将键对应的值置为空, 然后在某个时候删掉所有值为空的键), 或 即时删除 (立刻从表中删除指定的键). 在我们的实现中, 我们采用 即时删除.

5. 便捷方法

为简化用例, 我们再添加两个便捷方法:

方法 默认实现
void delete(Key key) put(key, null)
boolean contains(key) return get(key) != null;
bolean isEmpty() return size() == 0;

6. 迭代

为方便用例处理表中的所有键值, 我们强制所有实现必须包含 Iterable 接口.

7. 键的等价性

对于标准数据类型, 我们可以使用 Java 内置的等价性实现 equals(). 若需要自定义键, 就需要 重写 equals() 方法. 为了确保表的一致性, 最好使用 不可变的数据类型 作为键.


有序符号表