符号表可以使用链表来实现。

定义 API

API(public class SequentialSearch()) 功能
SequentialSearch() 创建一张符号表
void put(Key key, Value val) 将键值对存入表中(若值为空将键 Key 从表中删除)
Value get(Key key) 获取键 key 对应的值(若键 key 不存在则返回 null)
void delete(Key key) 从表中删去键 key(及其对的值)
boolean contains(Key key) 键 key 在表中是否有对应的值
boolean isEmpty() 表是否为空
int size() 表中的键值对数量

实现

  1. public class SequentialSearchST<Key, Value> {
  2. private int n = 0;
  3. private Node first = null;
  4. /**
  5. * 私有内部 Node 类来在链表中保存键和值。
  6. */
  7. private class Node {
  8. Key key;
  9. Value val;
  10. Node next;
  11. public Node(Key key, Value val, Node next) {
  12. this.key = key;
  13. this.val = val;
  14. this.next = next;
  15. }
  16. }
  17. /**
  18. * 顺序地搜索链表查找给定的键(找到则返回相关联的值)。
  19. * @param key
  20. * @return
  21. */
  22. public Value get(Key key) {
  23. for(Node x = first; x != null; x = x.next) {
  24. if(key.equals(x.key)) return x.val;
  25. }
  26. return null;
  27. }
  28. /**
  29. * 顺序地搜索链表查找给定的键,如果找到则更新相关联的值,否则用给定的键值对创建一个新的结点并将其插入到链表的开头。
  30. * @param key
  31. * @param val
  32. */
  33. public void put(Key key, Value val) {
  34. if(key == null) throw new IllegalArgumentException("first argument to put() is null");
  35. if(val == null) {
  36. delete(key);
  37. return;
  38. }
  39. for(Node x = first; x != null; x = x.next) {
  40. if(key.equals(x.key)) {
  41. x.val = val; return;
  42. }
  43. }
  44. first = new Node(key, val, first);
  45. n++; //链表大小加 1
  46. }
  47. public void delete(Key key) {
  48. if(key == null) throw new IllegalArgumentException("argument to delete() is null");
  49. first = delete(first, key);
  50. }
  51. /**
  52. * 递归实现删除方法,如果链表过大会导致爆栈。
  53. * @param x
  54. * @param key
  55. * @return
  56. */
  57. private Node delete(Node x, Key key) {
  58. if(x == null) return null;
  59. // 判断是否是删除第一个链表结点或者递归检测待删除结点与链表结点
  60. if(key.equals(x.key)) {
  61. n--;
  62. return x.next;
  63. }
  64. x.next = delete(x.next, key);
  65. return x;
  66. }
  67. /**
  68. * 返回符号表的大小
  69. * @return
  70. */
  71. public int size() {
  72. return n;
  73. }
  74. /**
  75. * 根据 size() 是否为 0 来判断。
  76. * @return
  77. */
  78. public boolean isEmpty() {
  79. return size() == 0;
  80. }
  81. public static void main(String[] args) {
  82. SequentialSearchST<Integer, String> st = new SequentialSearchST<>();
  83. for(int i = 0; i < 10; i++) {
  84. // 生成随机字符串
  85. int leftLimit = 97; // letter 'a'
  86. int rightLimit = 122; // letter 'z'
  87. int targetStringLength = 10;
  88. Random random = new Random();
  89. String generatedString = random.ints(leftLimit, rightLimit + 1)
  90. .limit(targetStringLength)
  91. .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
  92. .toString();
  93. st.put(i, generatedString);
  94. }
  95. System.out.println("st.size(): " + st.size());
  96. st.delete(1);
  97. System.out.println("st.size(): " + st.size());
  98. }
  99. }

使用链表实现符号表查找需要 链表实现符号表 - 图1 次比较,插入也是需要 链表实现符号表 - 图2 次比较。所以用链表实现是非常低效的。

参考: