? 书中第五章部分程序,包括在加上自己补充的代码,Trie 树类,Trie 集合,三值搜索树(Ternary Search Trie)
● Trie 树类
1 package package01; 2 3 import edu.princeton.cs.algs4.StdIn; 4 import edu.princeton.cs.algs4.StdOut; 5 import edu.princeton.cs.algs4.Queue; 6 7 public class class01<Value> 8 { 9 private static final int R = 256; // 扩展 ASCII 10 11 private Node root; 12 private int n; // 总节点数 13 14 private static class Node // 节点类,含当前节点代表的值,以及 R 路支链 15 { 16 private Object val; 17 private Node[] next = new Node[R]; 18 } 19 20 public class01() {} 21 22 public boolean contains(String key) 23 { 24 if (key == null) 25 throw new IllegalArgumentException("\n<contains> key == null.\n"); 26 return get(key) != null; 27 } 28 29 public Value get(String key) 30 { 31 if (key == null) 32 throw new IllegalArgumentException("\n<get> key == null.\n"); 33 Node x = getKernel(root, key, 0); 34 return (x == null) ? null : (Value)x.val; // 找到了就返回,没找到返回 null 35 } 36 37 private Node getKernel(Node x, String key, int d) // 注意返回的是节点,与 get 不同 38 { 39 if (x == null) // 先判断当前节点是否为空,再判断是否到达搜索终点,然后考虑递归 40 return null; 41 if (d == key.length()) 42 return x; 43 return getKernel(x.next[key.charAt(d)], key, d + 1); 44 } 45 46 public void put(String key, Value val) 47 { 48 if (key == null) 49 throw new IllegalArgumentException("\n<put> key == null.\n"); 50 if (val == null) 51 delete(key); 52 else 53 root = putKernel(root, key, val, 0); 54 } 55 56 private Node putKernel(Node x, String key, Value val, int d) 57 { 58 if (x == null) // 先判断当前节点是否为空,再判断是否到达搜索终点,然后考虑递归 59 x = new Node(); 60 if (d == key.length()) 61 { 62 if (x.val == null) // 节点为空,节点数 +1 63 n++; 64 x.val = val; // 赋上新值 65 } 66 else 67 { 68 char c = key.charAt(d); 69 x.next[c] = putKernel(x.next[c], key, val, d + 1); 70 } 71 return x; 72 } 73 74 public int size() 75 { 76 return n; 77 } 78 79 public boolean isEmpty() 80 { 81 return size() == 0; 82 } 83 84 public Iterable<String> keys() // 生成所有键的迭代器(遍历) 85 { 86 return keyPrefix(""); 87 } 88 89 public Iterable<String> keyPrefix(String prefix) // 生成具有给定前缀的所有键的迭代器 90 { 91 Queue<String> results = new Queue<String>(); 92 Node x = getKernel(root, prefix, 0); // 先抵达前缀结束时的搜索节点 93 collectPrefix(x, new StringBuilder(prefix), results); // 在此基础上遍历并放入迭代器 94 return results; 95 } 96 97 private void collectPrefix(Node x, StringBuilder prefix, Queue<String> results) // 遍历 x 为根节点的表,prefix 用来生成结果的,不参与遍历 98 { 99 if (x == null) 100 return; 101 if (x.val != null) 102 results.enqueue(prefix.toString()); // 除了给定前缀,没有多余字符的情况 103 for (char c = 0; c < R; c++) // 每次循环尝试添加一个字符,遍历子节点,然后删掉 104 { 105 prefix.append(c); 106 collectPrefix(x.next[c], prefix, results); 107 prefix.deleteCharAt(prefix.length() - 1); 108 } 109 } 110 111 public Iterable<String> keyPattern(String pattern) // 生成具有给定模式的所有键的迭代器 112 { 113 Queue<String> results = new Queue<String>(); 114 collectPattern(root, new StringBuilder(), pattern, results); 115 return results; 116 } 117 118 private void collectPattern(Node x, StringBuilder prefix, String pattern, Queue<String> results) 119 { 120 if (x == null) 121 return; 122 int d = prefix.length(); 123 if (d == pattern.length()) // 已经到了模式的尽头 124 { 125 if (x.val != null) 126 results.enqueue(prefix.toString()); 127 return; 128 } 129 char c = pattern.charAt(d); 130 if (c == ‘.‘) 131 { 132 for (char ch = 0; ch < R; ch++) // 模式是 ‘.‘,像 collectPrefix 那样尝试添加每一个字符来遍历子节点,然后删掉 133 { 134 prefix.append(ch); 135 collectPattern(x.next[ch], prefix, pattern, results); 136 prefix.deleteCharAt(prefix.length() - 1); 137 } 138 } 139 else // 否则只添加确定的字符,遍历其子节点,之后也要删掉 140 { 141 prefix.append(c); 142 collectPattern(x.next[c], prefix, pattern, results); 143 prefix.deleteCharAt(prefix.length() - 1); 144 } 145 } 146 147 public String longestPrefixOf(String query) // 找出与给定串有相同前缀的键的最大长度 148 { 149 if (query == null) 150 throw new IllegalArgumentException("\n<longestPrefixOf> query == null.\n"); 151 int length = longestPrefixOfKernel(root, query, 0, -1); 152 if (length == -1) 153 return null; 154 return query.substring(0, length); 155 } 156 157 private int longestPrefixOfKernel(Node x, String query, int d, int length) 158 { 159 if (x == null) 160 return length; 161 if (x.val != null) 162 length = d; 163 if (d == query.length()) 164 return length; 165 return longestPrefixOfKernel(x.next[query.charAt(d)], query, d + 1, length); 166 } 167 168 public void delete(String key) 169 { 170 if (key == null) 171 throw new IllegalArgumentException("\n<delete> key == null.\n"); 172 root = deleteKernel(root, key, 0); 173 } 174 175 private Node deleteKernel(Node x, String key, int d) // 删除节点 176 { 177 if (x == null) 178 return null; 179 if (d == key.length()) // 到达对应深度 180 { 181 if (x.val != null) // 目标节点存在,总结点数 -1 182 n--; 183 x.val = null; 184 } 185 else // 还没达到对应深度,继续下潜 186 { 187 char c = key.charAt(d); 188 x.next[c] = deleteKernel(x.next[c], key, d + 1); 189 } 190 if (x.val != null) // 返回途中,发现盖层 x 还没有被删,返回 x 191 return x; 192 for (int c = 0; c < R; c++) // x 已经被删,但是 x 还有子节点 193 { 194 if (x.next[c] != null) 195 return x; 196 } 197 return null; // x 已经被删,且没有子节点,返回 null 198 } 199 200 public static void main(String[] args) 201 { 202 class01<Integer> st = new class01<Integer>(); 203 for (int i = 0; !StdIn.isEmpty(); i++) // 输入键 204 st.put(StdIn.readString(), i); 205 if (st.size() < 100) // 输出保存的键 206 { 207 StdOut.println("keys(\"\"):"); 208 for (String key : st.keys()) 209 StdOut.println(key + " " + st.get(key)); 210 StdOut.println(); 211 } 212 213 StdOut.println("longestPrefixOf(\"shellsort\"):"); 214 StdOut.println(st.longestPrefixOf("shellsort")); 215 StdOut.println(); 216 217 StdOut.println("longestPrefixOf(\"quicksort\"):"); 218 StdOut.println(st.longestPrefixOf("quicksort")); 219 StdOut.println(); 220 221 StdOut.println("keyPrefix(\"shor\"):"); 222 for (String s : st.keyPrefix("shor")) 223 StdOut.println(s); 224 StdOut.println(); 225 226 StdOut.println("keyPattern(\".he.l.\"):"); 227 for (String s : st.keyPattern(".he.l.")) 228 StdOut.println(s); 229 } 230 }
● Trie 集合
1 package package01; 2 3 import java.util.Iterator; 4 import edu.princeton.cs.algs4.StdIn; 5 import edu.princeton.cs.algs4.StdOut; 6 import edu.princeton.cs.algs4.Queue; 7 8 public class class01 implements Iterable<String>// 需要 string 的迭代器 9 { 10 private static final int R = 256; 11 12 private Node root; 13 private int n; 14 15 private static class Node 16 { 17 private boolean isString; // 是否存在以当前节点为结尾的键 18 private Node[] next = new Node[R]; 19 } 20 21 public class01() {} 22 23 public boolean contains(String key) 24 { 25 if (key == null) 26 throw new IllegalArgumentException("\n<contains> key == null.\n"); 27 Node x = get(root, key, 0); 28 return (x == null) ? false : x.isString;// 是否为空的判断方式不同 29 } 30 31 private Node get(Node x, String key, int d) // 没有 get 和 getKernel 的区分 32 { 33 if (x == null) 34 return null; 35 if (d == key.length()) 36 return x; 37 return get(x.next[key.charAt(d)], key, d + 1); 38 } 39 40 public void put(String key)// 少了 val 参数 41 { 42 if (key == null) 43 throw new IllegalArgumentException("\n<put> key == null.\n"); 44 root = putKernel(root, key, 0); 45 } 46 47 private Node putKernel(Node x, String key, int d) 48 { 49 if (x == null) 50 x = new Node(); 51 if (d == key.length()) 52 { 53 if (!x.isString) // 是否为空的判断条件不同 54 n++; 55 x.isString = true; 56 } 57 else 58 { 59 char c = key.charAt(d); 60 x.next[c] = putKernel(x.next[c], key, d + 1); 61 } 62 return x; 63 } 64 65 public int size() 66 { 67 return n; 68 } 69 70 public boolean isEmpty() 71 { 72 return size() == 0; 73 } 74 75 public Iterator<String> iterator() // 不是 Iterable,Iterator 76 { 77 return keyPrefix("").iterator(); 78 } 79 80 public Iterable<String> keyPrefix(String prefix) 81 { 82 Queue<String> results = new Queue<String>(); 83 Node x = get(root, prefix, 0); 84 collectPrefix(x, new StringBuilder(prefix), results); 85 return results; 86 } 87 88 private void collectPrefix(Node x, StringBuilder prefix, Queue<String> results) 89 { 90 if (x == null) 91 return; 92 if (x.isString) 93 results.enqueue(prefix.toString()); 94 for (char c = 0; c < R; c++) 95 { 96 prefix.append(c); 97 collectPrefix(x.next[c], prefix, results); 98 prefix.deleteCharAt(prefix.length() - 1); 99 } 100 } 101 102 public Iterable<String> keyPattern(String pattern) 103 { 104 Queue<String> results = new Queue<String>(); 105 collectPattern(root, new StringBuilder(), pattern, results); 106 return results; 107 } 108 109 private void collectPattern(Node x, StringBuilder prefix, String pattern, Queue<String> results) 110 { 111 if (x == null) 112 return; 113 int d = prefix.length(); 114 if (d == pattern.length()) 115 { 116 if (x.isString) 117 results.enqueue(prefix.toString()); 118 return; 119 } 120 char c = pattern.charAt(d); 121 if (c == ‘.‘) 122 { 123 for (char ch = 0; ch < R; ch++) 124 { 125 prefix.append(ch); 126 collectPattern(x.next[ch], prefix, pattern, results); 127 prefix.deleteCharAt(prefix.length() - 1); 128 } 129 } 130 else 131 { 132 prefix.append(c); 133 collectPattern(x.next[c], prefix, pattern, results); 134 prefix.deleteCharAt(prefix.length() - 1); 135 } 136 } 137 138 public String longestPrefixOf(String query) 139 { 140 if (query == null) 141 throw new IllegalArgumentException("\n<longestPrefixOf> query == null.\n"); 142 int length = longestPrefixOfKernel(root, query, 0, -1); 143 if (length == -1) 144 return null; 145 return query.substring(0, length); 146 } 147 148 private int longestPrefixOfKernel(Node x, String query, int d, int length) 149 { 150 if (x == null) 151 return length; 152 if (x.isString) 153 length = d; 154 if (d == query.length()) 155 return length; 156 return longestPrefixOfKernel(x.next[query.charAt(d)], query, d+1, length); 157 } 158 159 public void delete(String key) 160 { 161 if (key == null) 162 throw new IllegalArgumentException("\n<delete> key == null.\n"); 163 root = deleteKernel(root, key, 0); 164 } 165 166 private Node deleteKernel(Node x, String key, int d) 167 { 168 if (x == null) 169 return null; 170 if (d == key.length()) 171 { 172 if (x.isString) 173 n--; 174 x.isString = false; 175 } 176 else 177 { 178 char c = key.charAt(d); 179 x.next[c] = deleteKernel(x.next[c], key, d+1); 180 } 181 if (x.isString) 182 return x; 183 for (int c = 0; c < R; c++) 184 { 185 if (x.next[c] != null) 186 return x; 187 } 188 return null; 189 } 190 191 public static void main(String[] args) 192 { 193 class01 st = new class01(); 194 for (; !StdIn.isEmpty(); st.put(StdIn.readString())); 195 if (st.size() < 100) 196 { 197 StdOut.println("keys(\"\"):"); 198 for (String key : st) 199 StdOut.println(key); 200 StdOut.println(); 201 } 202 203 StdOut.println("longestPrefixOf(\"shellsort\"):"); 204 StdOut.println(st.longestPrefixOf("shellsort")); 205 StdOut.println(); 206 207 StdOut.println("longestPrefixOf(\"xshellsort\"):"); 208 StdOut.println(st.longestPrefixOf("xshellsort")); 209 StdOut.println(); 210 211 StdOut.println("keyPrefix(\"shor\"):"); 212 for (String s : st.keyPrefix("shor")) 213 StdOut.println(s); 214 StdOut.println(); 215 216 StdOut.println("keyPrefix(\"shortening\"):"); 217 for (String s : st.keyPrefix("shortening")) 218 StdOut.println(s); 219 StdOut.println(); 220 221 StdOut.println("keyPattern(\".he.l.\"):"); 222 for (String s : st.keyPattern(".he.l.")) 223 StdOut.println(s); 224 } 225 }
● 三值搜索树
1 package package01; 2 3 import edu.princeton.cs.algs4.StdIn; 4 import edu.princeton.cs.algs4.StdOut; 5 import edu.princeton.cs.algs4.Queue; 6 7 public class class01<Value> 8 { 9 private Node<Value> root; 10 private int n; 11 12 private static class Node<Value> 13 { 14 private char c; 15 private Node<Value> left, mid, right; 16 private Value val; 17 } 18 19 public class01() {} 20 21 public boolean contains(String key) 22 { 23 if (key == null) 24 throw new IllegalArgumentException("\n<contains> key == null.\n"); 25 return get(key) != null; 26 } 27 28 public Value get(String key) 29 { 30 if (key == null || key.length() == 0) 31 throw new IllegalArgumentException("\n<get> key == null || key.length() == 0.\n"); 32 Node<Value> x = getKernel(root, key, 0); 33 return (x == null) ? null : x.val; 34 } 35 36 private Node<Value> getKernel(Node<Value> x, String key, int d) 37 { 38 if (x == null) 39 return null; 40 char c = key.charAt(d); 41 if (c < x.c) 42 return getKernel(x.left, key, d); // 向左右搜索的时候深度不变 43 if (c > x.c) 44 return getKernel(x.right, key, d); 45 if (d < key.length() - 1) 46 return getKernel(x.mid, key, d + 1); // 向中路搜索的时候深度要变化 47 return x; 48 } 49 50 public void put(String key, Value val) 51 { 52 if (key == null) 53 throw new IllegalArgumentException("\n<put> key == null.\n"); 54 if (!contains(key)) 55 n++; 56 root = putKernel(root, key, val, 0); 57 } 58 59 private Node<Value> putKernel(Node<Value> x, String key, Value val, int d) 60 { 61 char c = key.charAt(d); 62 if (x == null) 63 { 64 x = new Node<Value>(); 65 x.c = c; 66 } 67 if (c < x.c) 68 x.left = putKernel(x.left, key, val, d); 69 else if (c > x.c) 70 x.right = putKernel(x.right, key, val, d); 71 else if (d < key.length() - 1) 72 x.mid = putKernel(x.mid, key, val, d + 1); 73 else 74 x.val = val; 75 return x; 76 } 77 78 public int size() 79 { 80 return n; 81 } 82 83 public boolean isEmpty() 84 { 85 return size() == 0; 86 } 87 88 public Iterable<String> keys() // 需要直接从前缀中去字符参加比较,不能用 keyPrefix("") 89 { 90 Queue<String> queue = new Queue<String>(); 91 collectPrefix(root, new StringBuilder(), queue); 92 return queue; 93 } 94 95 public Iterable<String> keyPrefix(String prefix) 96 { 97 Queue<String> queue = new Queue<String>(); 98 Node<Value> x = getKernel(root, prefix, 0); 99 if (x == null) 100 return queue; 101 if (x.val != null) 102 queue.enqueue(prefix); 103 collectPrefix(x.mid, new StringBuilder(prefix), queue); 104 return queue; 105 } 106 107 private void collectPrefix(Node<Value> x, StringBuilder prefix, Queue<String> queue) 108 { 109 if (x == null) 110 return; 111 collectPrefix(x.left, prefix, queue); 112 if (x.val != null) 113 queue.enqueue(prefix.toString() + x.c); 114 collectPrefix(x.mid, prefix.append(x.c), queue); 115 prefix.deleteCharAt(prefix.length() - 1); 116 collectPrefix(x.right, prefix, queue); 117 } 118 119 public Iterable<String> keyPattern(String pattern) 120 { 121 Queue<String> queue = new Queue<String>(); 122 collectPattern(root, new StringBuilder(), 0, pattern, queue); 123 return queue; 124 } 125 126 private void collectPattern(Node<Value> x, StringBuilder prefix, int i, String pattern, Queue<String> queue) 127 { 128 if (x == null) 129 return; 130 char c = pattern.charAt(i); 131 if (c == ‘.‘ || c < x.c) // 分解为 c 和 x.c 的三种情况,插上 ‘.‘ 的情况 132 collectPattern(x.left, prefix, i, pattern, queue); 133 if (c == ‘.‘ || c == x.c) 134 { 135 if (i == pattern.length() - 1 && x.val != null) 136 queue.enqueue(prefix.toString() + x.c); 137 if (i < pattern.length() - 1) 138 { 139 collectPattern(x.mid, prefix.append(x.c), i + 1, pattern, queue); 140 prefix.deleteCharAt(prefix.length() - 1); 141 } 142 } 143 if (c == ‘.‘ || c > x.c) 144 collectPattern(x.right, prefix, i, pattern, queue); 145 } 146 147 public String longestPrefixOf(String query) 148 { 149 if (query == null || query.length() == 0) 150 throw new IllegalArgumentException("\n<longestPrefixOf> query == null || query.length() == 0.\n"); 151 int length = 0; 152 Node<Value> x = root; 153 for (int i = 0; x != null && i < query.length();) // i 为当前匹配的长度 154 { 155 char c = query.charAt(i); 156 if (c < x.c) 157 x = x.left; 158 else if (c > x.c) 159 x = x.right; 160 else 161 { 162 i++; 163 if (x.val != null) 164 length = i; 165 x = x.mid; 166 } 167 } 168 return query.substring(0, length); 169 } 170 171 public static void main(String[] args) 172 { 173 class01<Integer> st = new class01<Integer>(); 174 for (int i = 0; !StdIn.isEmpty(); i++) 175 { 176 String key = StdIn.readString(); 177 st.put(key, i); 178 } 179 180 if (st.size() < 100) 181 { 182 StdOut.println("keys(\"\"):"); 183 for (String key : st.keys()) 184 StdOut.println(key + " " + st.get(key)); 185 StdOut.println(); 186 } 187 188 StdOut.println("longestPrefixOf(\"shellsort\"):"); 189 StdOut.println(st.longestPrefixOf("shellsort")); 190 StdOut.println(); 191 192 StdOut.println("longestPrefixOf(\"shell\"):"); 193 StdOut.println(st.longestPrefixOf("shell")); 194 StdOut.println(); 195 196 StdOut.println("keysWithPrefix(\"shor\"):"); 197 for (String s : st.keyPrefix("shor")) 198 StdOut.println(s); 199 StdOut.println(); 200 201 StdOut.println("keysThatMatch(\".he.l.\"):"); 202 for (String s : st.keyPattern(".he.l.")) 203 StdOut.println(s); 204 } 205 }
原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9869294.html
时间: 2024-11-08 13:12:43