《算法》第五章部分程序 part 4
▶ 书中第五章部分程序,包括在加上自己补充的代码,Trie 树类,Trie 集合,三值搜索树(Ternary Search Trie)
● Trie 树类
package package01; import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.Queue; public class class01<Value>
{
private static final int R = 256; // 扩展 ASCII private Node root;
private int n; // 总节点数 private static class Node // 节点类,含当前节点代表的值,以及 R 路支链
{
private Object val;
private Node[] next = new Node[R];
} public class01() {} public boolean contains(String key)
{
if (key == null)
throw new IllegalArgumentException("\n<contains> key == null.\n");
return get(key) != null;
} public Value get(String key)
{
if (key == null)
throw new IllegalArgumentException("\n<get> key == null.\n");
Node x = getKernel(root, key, 0);
return (x == null) ? null : (Value)x.val; // 找到了就返回,没找到返回 null
} private Node getKernel(Node x, String key, int d) // 注意返回的是节点,与 get 不同
{
if (x == null) // 先判断当前节点是否为空,再判断是否到达搜索终点,然后考虑递归
return null;
if (d == key.length())
return x;
return getKernel(x.next[key.charAt(d)], key, d + 1);
} public void put(String key, Value val)
{
if (key == null)
throw new IllegalArgumentException("\n<put> key == null.\n");
if (val == null)
delete(key);
else
root = putKernel(root, key, val, 0);
} private Node putKernel(Node x, String key, Value val, int d)
{
if (x == null) // 先判断当前节点是否为空,再判断是否到达搜索终点,然后考虑递归
x = new Node();
if (d == key.length())
{
if (x.val == null) // 节点为空,节点数 +1
n++;
x.val = val; // 赋上新值
}
else
{
char c = key.charAt(d);
x.next[c] = putKernel(x.next[c], key, val, d + 1);
}
return x;
} public int size()
{
return n;
} public boolean isEmpty()
{
return size() == 0;
} public Iterable<String> keys() // 生成所有键的迭代器(遍历)
{
return keyPrefix("");
} public Iterable<String> keyPrefix(String prefix) // 生成具有给定前缀的所有键的迭代器
{
Queue<String> results = new Queue<String>();
Node x = getKernel(root, prefix, 0); // 先抵达前缀结束时的搜索节点
collectPrefix(x, new StringBuilder(prefix), results); // 在此基础上遍历并放入迭代器
return results;
} private void collectPrefix(Node x, StringBuilder prefix, Queue<String> results) // 遍历 x 为根节点的表,prefix 用来生成结果的,不参与遍历
{
if (x == null)
return;
if (x.val != null)
results.enqueue(prefix.toString()); // 除了给定前缀,没有多余字符的情况
for (char c = 0; c < R; c++) // 每次循环尝试添加一个字符,遍历子节点,然后删掉
{
prefix.append(c);
collectPrefix(x.next[c], prefix, results);
prefix.deleteCharAt(prefix.length() - 1);
}
} public Iterable<String> keyPattern(String pattern) // 生成具有给定模式的所有键的迭代器
{
Queue<String> results = new Queue<String>();
collectPattern(root, new StringBuilder(), pattern, results);
return results;
} private void collectPattern(Node x, StringBuilder prefix, String pattern, Queue<String> results)
{
if (x == null)
return;
int d = prefix.length();
if (d == pattern.length()) // 已经到了模式的尽头
{
if (x.val != null)
results.enqueue(prefix.toString());
return;
}
char c = pattern.charAt(d);
if (c == '.')
{
for (char ch = 0; ch < R; ch++) // 模式是 '.',像 collectPrefix 那样尝试添加每一个字符来遍历子节点,然后删掉
{
prefix.append(ch);
collectPattern(x.next[ch], prefix, pattern, results);
prefix.deleteCharAt(prefix.length() - 1);
}
}
else // 否则只添加确定的字符,遍历其子节点,之后也要删掉
{
prefix.append(c);
collectPattern(x.next[c], prefix, pattern, results);
prefix.deleteCharAt(prefix.length() - 1);
}
} public String longestPrefixOf(String query) // 找出与给定串有相同前缀的键的最大长度
{
if (query == null)
throw new IllegalArgumentException("\n<longestPrefixOf> query == null.\n");
int length = longestPrefixOfKernel(root, query, 0, -1);
if (length == -1)
return null;
return query.substring(0, length);
} private int longestPrefixOfKernel(Node x, String query, int d, int length)
{
if (x == null)
return length;
if (x.val != null)
length = d;
if (d == query.length())
return length;
return longestPrefixOfKernel(x.next[query.charAt(d)], query, d + 1, length);
} public void delete(String key)
{
if (key == null)
throw new IllegalArgumentException("\n<delete> key == null.\n");
root = deleteKernel(root, key, 0);
} private Node deleteKernel(Node x, String key, int d) // 删除节点
{
if (x == null)
return null;
if (d == key.length()) // 到达对应深度
{
if (x.val != null) // 目标节点存在,总结点数 -1
n--;
x.val = null;
}
else // 还没达到对应深度,继续下潜
{
char c = key.charAt(d);
x.next[c] = deleteKernel(x.next[c], key, d + 1);
}
if (x.val != null) // 返回途中,发现盖层 x 还没有被删,返回 x
return x;
for (int c = 0; c < R; c++) // x 已经被删,但是 x 还有子节点
{
if (x.next[c] != null)
return x;
}
return null; // x 已经被删,且没有子节点,返回 null
} public static void main(String[] args)
{
class01<Integer> st = new class01<Integer>();
for (int i = 0; !StdIn.isEmpty(); i++) // 输入键
st.put(StdIn.readString(), i);
if (st.size() < 100) // 输出保存的键
{
StdOut.println("keys(\"\"):");
for (String key : st.keys())
StdOut.println(key + " " + st.get(key));
StdOut.println();
} StdOut.println("longestPrefixOf(\"shellsort\"):");
StdOut.println(st.longestPrefixOf("shellsort"));
StdOut.println(); StdOut.println("longestPrefixOf(\"quicksort\"):");
StdOut.println(st.longestPrefixOf("quicksort"));
StdOut.println(); StdOut.println("keyPrefix(\"shor\"):");
for (String s : st.keyPrefix("shor"))
StdOut.println(s);
StdOut.println(); StdOut.println("keyPattern(\".he.l.\"):");
for (String s : st.keyPattern(".he.l."))
StdOut.println(s);
}
}
● Trie 集合
package package01; import java.util.Iterator;
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.Queue; public class class01 implements Iterable<String>// 需要 string 的迭代器
{
private static final int R = 256; private Node root;
private int n; private static class Node
{
private boolean isString; // 是否存在以当前节点为结尾的键
private Node[] next = new Node[R];
} public class01() {} public boolean contains(String key)
{
if (key == null)
throw new IllegalArgumentException("\n<contains> key == null.\n");
Node x = get(root, key, 0);
return (x == null) ? false : x.isString;// 是否为空的判断方式不同
} private Node get(Node x, String key, int d) // 没有 get 和 getKernel 的区分
{
if (x == null)
return null;
if (d == key.length())
return x;
return get(x.next[key.charAt(d)], key, d + 1);
} public void put(String key)// 少了 val 参数
{
if (key == null)
throw new IllegalArgumentException("\n<put> key == null.\n");
root = putKernel(root, key, 0);
} private Node putKernel(Node x, String key, int d)
{
if (x == null)
x = new Node();
if (d == key.length())
{
if (!x.isString) // 是否为空的判断条件不同
n++;
x.isString = true;
}
else
{
char c = key.charAt(d);
x.next[c] = putKernel(x.next[c], key, d + 1);
}
return x;
} public int size()
{
return n;
} public boolean isEmpty()
{
return size() == 0;
} public Iterator<String> iterator() // 不是 Iterable,Iterator
{
return keyPrefix("").iterator();
} public Iterable<String> keyPrefix(String prefix)
{
Queue<String> results = new Queue<String>();
Node x = get(root, prefix, 0);
collectPrefix(x, new StringBuilder(prefix), results);
return results;
} private void collectPrefix(Node x, StringBuilder prefix, Queue<String> results)
{
if (x == null)
return;
if (x.isString)
results.enqueue(prefix.toString());
for (char c = 0; c < R; c++)
{
prefix.append(c);
collectPrefix(x.next[c], prefix, results);
prefix.deleteCharAt(prefix.length() - 1);
}
} public Iterable<String> keyPattern(String pattern)
{
Queue<String> results = new Queue<String>();
collectPattern(root, new StringBuilder(), pattern, results);
return results;
} private void collectPattern(Node x, StringBuilder prefix, String pattern, Queue<String> results)
{
if (x == null)
return;
int d = prefix.length();
if (d == pattern.length())
{
if (x.isString)
results.enqueue(prefix.toString());
return;
}
char c = pattern.charAt(d);
if (c == '.')
{
for (char ch = 0; ch < R; ch++)
{
prefix.append(ch);
collectPattern(x.next[ch], prefix, pattern, results);
prefix.deleteCharAt(prefix.length() - 1);
}
}
else
{
prefix.append(c);
collectPattern(x.next[c], prefix, pattern, results);
prefix.deleteCharAt(prefix.length() - 1);
}
} public String longestPrefixOf(String query)
{
if (query == null)
throw new IllegalArgumentException("\n<longestPrefixOf> query == null.\n");
int length = longestPrefixOfKernel(root, query, 0, -1);
if (length == -1)
return null;
return query.substring(0, length);
} private int longestPrefixOfKernel(Node x, String query, int d, int length)
{
if (x == null)
return length;
if (x.isString)
length = d;
if (d == query.length())
return length;
return longestPrefixOfKernel(x.next[query.charAt(d)], query, d+1, length);
} public void delete(String key)
{
if (key == null)
throw new IllegalArgumentException("\n<delete> key == null.\n");
root = deleteKernel(root, key, 0);
} private Node deleteKernel(Node x, String key, int d)
{
if (x == null)
return null;
if (d == key.length())
{
if (x.isString)
n--;
x.isString = false;
}
else
{
char c = key.charAt(d);
x.next[c] = deleteKernel(x.next[c], key, d+1);
}
if (x.isString)
return x;
for (int c = 0; c < R; c++)
{
if (x.next[c] != null)
return x;
}
return null;
} public static void main(String[] args)
{
class01 st = new class01();
for (; !StdIn.isEmpty(); st.put(StdIn.readString()));
if (st.size() < 100)
{
StdOut.println("keys(\"\"):");
for (String key : st)
StdOut.println(key);
StdOut.println();
} StdOut.println("longestPrefixOf(\"shellsort\"):");
StdOut.println(st.longestPrefixOf("shellsort"));
StdOut.println(); StdOut.println("longestPrefixOf(\"xshellsort\"):");
StdOut.println(st.longestPrefixOf("xshellsort"));
StdOut.println(); StdOut.println("keyPrefix(\"shor\"):");
for (String s : st.keyPrefix("shor"))
StdOut.println(s);
StdOut.println(); StdOut.println("keyPrefix(\"shortening\"):");
for (String s : st.keyPrefix("shortening"))
StdOut.println(s);
StdOut.println(); StdOut.println("keyPattern(\".he.l.\"):");
for (String s : st.keyPattern(".he.l."))
StdOut.println(s);
}
}
● 三值搜索树
package package01; import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.Queue; public class class01<Value>
{
private Node<Value> root;
private int n; private static class Node<Value>
{
private char c;
private Node<Value> left, mid, right;
private Value val;
} public class01() {} public boolean contains(String key)
{
if (key == null)
throw new IllegalArgumentException("\n<contains> key == null.\n");
return get(key) != null;
} public Value get(String key)
{
if (key == null || key.length() == 0)
throw new IllegalArgumentException("\n<get> key == null || key.length() == 0.\n");
Node<Value> x = getKernel(root, key, 0);
return (x == null) ? null : x.val;
} private Node<Value> getKernel(Node<Value> x, String key, int d)
{
if (x == null)
return null;
char c = key.charAt(d);
if (c < x.c)
return getKernel(x.left, key, d); // 向左右搜索的时候深度不变
if (c > x.c)
return getKernel(x.right, key, d);
if (d < key.length() - 1)
return getKernel(x.mid, key, d + 1); // 向中路搜索的时候深度要变化
return x;
} public void put(String key, Value val)
{
if (key == null)
throw new IllegalArgumentException("\n<put> key == null.\n");
if (!contains(key))
n++;
root = putKernel(root, key, val, 0);
} private Node<Value> putKernel(Node<Value> x, String key, Value val, int d)
{
char c = key.charAt(d);
if (x == null)
{
x = new Node<Value>();
x.c = c;
}
if (c < x.c)
x.left = putKernel(x.left, key, val, d);
else if (c > x.c)
x.right = putKernel(x.right, key, val, d);
else if (d < key.length() - 1)
x.mid = putKernel(x.mid, key, val, d + 1);
else
x.val = val;
return x;
} public int size()
{
return n;
} public boolean isEmpty()
{
return size() == 0;
} public Iterable<String> keys() // 需要直接从前缀中去字符参加比较,不能用 keyPrefix("")
{
Queue<String> queue = new Queue<String>();
collectPrefix(root, new StringBuilder(), queue);
return queue;
} public Iterable<String> keyPrefix(String prefix)
{
Queue<String> queue = new Queue<String>();
Node<Value> x = getKernel(root, prefix, 0);
if (x == null)
return queue;
if (x.val != null)
queue.enqueue(prefix);
collectPrefix(x.mid, new StringBuilder(prefix), queue);
return queue;
} private void collectPrefix(Node<Value> x, StringBuilder prefix, Queue<String> queue)
{
if (x == null)
return;
collectPrefix(x.left, prefix, queue);
if (x.val != null)
queue.enqueue(prefix.toString() + x.c);
collectPrefix(x.mid, prefix.append(x.c), queue);
prefix.deleteCharAt(prefix.length() - 1);
collectPrefix(x.right, prefix, queue);
} public Iterable<String> keyPattern(String pattern)
{
Queue<String> queue = new Queue<String>();
collectPattern(root, new StringBuilder(), 0, pattern, queue);
return queue;
} private void collectPattern(Node<Value> x, StringBuilder prefix, int i, String pattern, Queue<String> queue)
{
if (x == null)
return;
char c = pattern.charAt(i);
if (c == '.' || c < x.c) // 分解为 c 和 x.c 的三种情况,插上 '.' 的情况
collectPattern(x.left, prefix, i, pattern, queue);
if (c == '.' || c == x.c)
{
if (i == pattern.length() - 1 && x.val != null)
queue.enqueue(prefix.toString() + x.c);
if (i < pattern.length() - 1)
{
collectPattern(x.mid, prefix.append(x.c), i + 1, pattern, queue);
prefix.deleteCharAt(prefix.length() - 1);
}
}
if (c == '.' || c > x.c)
collectPattern(x.right, prefix, i, pattern, queue);
} public String longestPrefixOf(String query)
{
if (query == null || query.length() == 0)
throw new IllegalArgumentException("\n<longestPrefixOf> query == null || query.length() == 0.\n");
int length = 0;
Node<Value> x = root;
for (int i = 0; x != null && i < query.length();) // i 为当前匹配的长度
{
char c = query.charAt(i);
if (c < x.c)
x = x.left;
else if (c > x.c)
x = x.right;
else
{
i++;
if (x.val != null)
length = i;
x = x.mid;
}
}
return query.substring(0, length);
} public static void main(String[] args)
{
class01<Integer> st = new class01<Integer>();
for (int i = 0; !StdIn.isEmpty(); i++)
{
String key = StdIn.readString();
st.put(key, i);
} if (st.size() < 100)
{
StdOut.println("keys(\"\"):");
for (String key : st.keys())
StdOut.println(key + " " + st.get(key));
StdOut.println();
} StdOut.println("longestPrefixOf(\"shellsort\"):");
StdOut.println(st.longestPrefixOf("shellsort"));
StdOut.println(); StdOut.println("longestPrefixOf(\"shell\"):");
StdOut.println(st.longestPrefixOf("shell"));
StdOut.println(); StdOut.println("keysWithPrefix(\"shor\"):");
for (String s : st.keyPrefix("shor"))
StdOut.println(s);
StdOut.println(); StdOut.println("keysThatMatch(\".he.l.\"):");
for (String s : st.keyPattern(".he.l."))
StdOut.println(s);
}
}
《算法》第五章部分程序 part 4的更多相关文章
- 《算法》第五章部分程序 part 3
▶ 书中第五章部分程序,包括在加上自己补充的代码,字符串高位优先排序(美国国旗排序) ● 美国国旗排序 package package01; import edu.princeton.cs.algs4 ...
- 《算法》第五章部分程序 part 8
▶ 书中第五章部分程序,包括在加上自己补充的代码,适用于基因序列的 2-Bit 压缩算法,行程长压缩算法,Huffman 压缩算法,LZW 压缩算法 ● 适用于基因序列的 2-Bit 压缩算法 pac ...
- 《算法》第五章部分程序 part 7
▶ 书中第五章部分程序,包括在加上自己补充的代码,字符串的二进制表示.十六进制表示.图形表示 ● 二进制表示 package package01; import edu.princeton.cs.al ...
- 《算法》第五章部分程序 part 6
▶ 书中第五章部分程序,包括在加上自己补充的代码,非确定性有穷自动机(NFA),grep 命令(利用 NFA 匹配) ● 非确定性有穷自动机(NFA) package package01; impor ...
- 《算法》第五章部分程序 part 5
▶ 书中第五章部分程序,包括在加上自己补充的代码,Knuth-Morris-Pratt 无回溯匹配,Boyer - Moore 无回溯匹配,Rabin - Karp 指纹匹配 ● Knuth-Morr ...
- 《算法》第五章部分程序 part 2
▶ 书中第五章部分程序,包括在加上自己补充的代码,字符串高位优先排序(计数 + 插排),(原地排序),(三路快排,与前面的三路归并排序相同) ● 计数 + 插排 package package01; ...
- 《算法》第五章部分程序 part 1
▶ 书中第五章部分程序,包括在加上自己补充的代码,字母表类,字符串低位优先排序(桶排) ● 字母表类 package package01; import edu.princeton.cs.algs4. ...
- Gradle 1.12用户指南翻译——第四十五章. 应用程序插件
本文由CSDN博客貌似掉线翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...
- 《算法》第一章部分程序 part 1
▶ 书中第一章部分程序,加上自己补充的代码,包括若干种二分搜索,寻找图上连通分量数的两种算法 ● 代码,二分搜索 package package01; import java.util.Arrays; ...
随机推荐
- linux在线中文手册
linux在线中文手册 http://linux.51yip.com/ 百度中的百度应用也不错 http://www.baidu.com/s?word=linux%E5%91%BD%E4%BB%A4& ...
- 【git之】fetch和 pull的区别
Git中从远程的分支获取最新的版本到本地有这样2个命令:1. git fetch:相当于是从远程获取最新版本到本地,不会自动merge Git fetch origin master git log ...
- 【JVM】Class结构之常量池
常量池 主要包括下面2类: 字面量(Literal):如int,double,String等: 符号引用(Symbolic Reference): 符号引用 类和接口的全限定名: 字段的名称和描述符: ...
- Hadoop 管理工具HUE配置-filebrowser配置
Hue提供了图形化截面管理HDFS数据,可谓之非常方便,但是在配置上,还是有点麻烦的. 1 /home/hadoop/software/cloud/hue/desktop/conf/pseudo-di ...
- IP地址与无符号整数值相互转换
方法1:IP地址转换为整数:比如"192.168.1.254",以点为分割,将192 168 1 254保存在一个int a[4]数组里,然后通过unsigned int nRes ...
- elasticsearch 安装(基于java运行环境)
解压安装包 [root@Aliyun resource]# tar -xvf elasticsearch-5.5.2.tar.gz 添加当前主机的普通账户 [root@Aliyun resource] ...
- spring4.0之七:Ordering Autowired Collections
Spring 4.0的一个小特性是在自动注入的时候使用@Order.Spring 2.5中,我们将bean注入List,如下代码: import org.springframework.stereot ...
- OpenStack 创建虚机过程简要汇总
1. 总体流程 翻译自原文(英文):https://ilearnstack.com/2013/04/26/request-flow-for-provisioning-instance-in-opens ...
- ping一个网段的cmd程序
ping一个网段的cmd程序 今天发现只在cmd命令行工具中输入: FOR /L %i IN (1,1,254) DO ping -n 1 192.168.1.%i 即可.
- php的方法
字符串: strlen(): 字符串的个数: . : 通过.来进行字符串的拼接: 数组: count(): 数组的 个数: is_array(): 判断是不是一个数组: 实参的方法: func_num ...