链表实现无序符号表
实现原理
- 使用一个私有内部Node类来在链表中保存键值对
- get()的实现会顺序的搜索链表查找给定的 键
- put()的实现也会顺序的搜索给定的键,如果找到则更新,否则会将给定的键值对插入链表的开头
- delete()的实现同样是顺序的搜索给定的键,如果找到则将链表的的next更新为此时它的父级的next
- keys() 的实现使用队列 FIFO 的特性保证当前符号表中Key的位置;队列实现
复杂度
-
在还有 N N N 对键值对的基于(无序)链表的符号表中,未命中的查找和插入操作都需要 N N N次比较。命中的查找在最坏情况下的情况下需要 N N N次比较。特别地,向一个空表中插入 N N N个不同的键需要 N 2 / 2 ~ N^2/2 N2/2次比较
基于以上分析完全证明了基于链表的实现以及顺序查找是非常低效的,无法满足处理庞大输入的问题的需求
Java实现
/**
* 链表实现的(顺序查找)符号表
*/
public class LinkedSequentialSearchST<Key, Value> implements ISymbolTable<Key, Value> {
/**
* 符号表中键值对的个数
*/
private int n;
/**
* 键值对链表
*/
private Node first;
private class Node {
private Key key;
private Value value;
private Node next;
public Node(Key key, Value value, Node next) {
this.key = key;
this.value = value;
this.next = next;
}
}
public LinkedSequentialSearchST() {
n = 0;
}
/**
* 将键值对存入符号表(如果值为空则将键从表中删除)
*
* @param key
* 键
* @param value
* 值
*/
@Override
public void put(Key key, Value value) {
validKey(key);
if (value == null) {
delete(key);
return;
}
// 顺序的依次查找key,如果匹配替换旧值
for (Node x = first; x != null; x = x.next) {
if (key.equals(x.key)) {
x.value = value;
return;
}
}
// 如果未找到key,将键值对放在链表的顶部
first = new Node(key, value, first);
n++;
}
/***
* 获取键 key 的值(如果键 key 不存在则返回 null)
*
* @param key
* 键
* @return 对应的值
*/
@Override
public Value get(Key key) {
validKey(key);
// 顺序的查找key,如果找到返回对应的Value,否则返回null
for (Node x = first; x != null; x = x.next) {
if (key.equals(x.key)) {
return x.value;
}
}
return null;
}
/**
* 从符号表中删除键 key(以及对应的值)
*
* @param key
* 键
*/
@Override
public void delete(Key key) {
validKey(key);
first = delete(first, key);
}
/**
* 键key是否在符号表中有对应的值
*
* @param key
* 键
* @return boolean
*/
@Override
public boolean contains(Key key) {
validKey(key);
return get(key) != null;
}
/**
* 返回符号表是否为空
*
* @return boolean
*/
@Override
public boolean isEmpty() {
return n == 0;
}
/**
* 返回符号表中键值对的个数
*
* @return 符号表中键值对的个数
*/
@Override
public int size() {
return n;
}
/**
* 返回符号表中所有键的(可迭代)集合
* 使用队列 FIFO 的特性保证当前符号表中key的位置
*
* @return 键的集合
*/
@Override
public Iterable<Key> keys() {
LinkedQueue<Key> queue = new LinkedQueue<>();
for (Node x = first; x != null; x = x.next) {
queue.enqueue(x.key);
}
return queue;
}
private void validKey(Key key) {
if (key == null) {
throw new IllegalArgumentException();
}
}
private Node delete(Node x, Key key) {
if (x == null) {
return null;
}
if (key.equals(x.key)) {
n--;
return x.next;
}
x.next = delete(x.next, key);
return x;
}
}