▶ 书中第五章部分程序,包括在加上自己补充的代码,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的更多相关文章

  1. 《算法》第五章部分程序 part 3

    ▶ 书中第五章部分程序,包括在加上自己补充的代码,字符串高位优先排序(美国国旗排序) ● 美国国旗排序 package package01; import edu.princeton.cs.algs4 ...

  2. 《算法》第五章部分程序 part 8

    ▶ 书中第五章部分程序,包括在加上自己补充的代码,适用于基因序列的 2-Bit 压缩算法,行程长压缩算法,Huffman 压缩算法,LZW 压缩算法 ● 适用于基因序列的 2-Bit 压缩算法 pac ...

  3. 《算法》第五章部分程序 part 7

    ▶ 书中第五章部分程序,包括在加上自己补充的代码,字符串的二进制表示.十六进制表示.图形表示 ● 二进制表示 package package01; import edu.princeton.cs.al ...

  4. 《算法》第五章部分程序 part 6

    ▶ 书中第五章部分程序,包括在加上自己补充的代码,非确定性有穷自动机(NFA),grep 命令(利用 NFA 匹配) ● 非确定性有穷自动机(NFA) package package01; impor ...

  5. 《算法》第五章部分程序 part 5

    ▶ 书中第五章部分程序,包括在加上自己补充的代码,Knuth-Morris-Pratt 无回溯匹配,Boyer - Moore 无回溯匹配,Rabin - Karp 指纹匹配 ● Knuth-Morr ...

  6. 《算法》第五章部分程序 part 2

    ▶ 书中第五章部分程序,包括在加上自己补充的代码,字符串高位优先排序(计数 + 插排),(原地排序),(三路快排,与前面的三路归并排序相同) ● 计数 + 插排 package package01; ...

  7. 《算法》第五章部分程序 part 1

    ▶ 书中第五章部分程序,包括在加上自己补充的代码,字母表类,字符串低位优先排序(桶排) ● 字母表类 package package01; import edu.princeton.cs.algs4. ...

  8. Gradle 1.12用户指南翻译——第四十五章. 应用程序插件

    本文由CSDN博客貌似掉线翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...

  9. 《算法》第一章部分程序 part 1

    ▶ 书中第一章部分程序,加上自己补充的代码,包括若干种二分搜索,寻找图上连通分量数的两种算法 ● 代码,二分搜索 package package01; import java.util.Arrays; ...

随机推荐

  1. Azure REST API (3) 使用REST API,操作Azure ARM VM

    <Windows Azure Platform 系列文章目录> 笔者之前遇到一个客户,需求是当发生某一个特定条件的时候,对多台Azure ARM VM执行开机或者关机操作,这个时候就需要使 ...

  2. VS2017 远程调试linux(centos).net core

    第一步建立链接 Tools > Options > Cross Platform > Connection Manage 工具>选项>跨平台>连接管理器 第二步骤  ...

  3. sysroot和prefix

    --with-sysroot用来指定系统的root.该选项主要用于新系统(比如LFS)构建或交叉编译.比如你的LFS的root在/mnt/lfs,那么configure时指定--with-sysroo ...

  4. 还原MongoDB dump备份出来的Bson数据

    集合名 数据库名 备份文件位置 mongorestore --collection people --db accounts dump/accounts/people.bson

  5. javac命令和java命令

    要知道java是分两部分的:一个是编译,一个是运行. javac:负责的是编译的部分,当执行javac时,会启动java的编译器程序.对指定扩展名的.java文件进行编译. 生成了jvm可以识别的字节 ...

  6. SQL优化系列——索引

    索引可能是数据库中最被误解的主题,因为有很多方式让你糊涂索引如何工作,以及服务器如何使用它们.要正确设计索引,让索引在数据库服务器中满足以下三个重要目的:1,索引使服务器查找一组相邻行,而不是单独的行 ...

  7. 解决python中路径中包含中文无法找到文件的问题

    a="C:\Users\Dell\Desktop\ATOU\公共测试用例" (带中文的路径) a=a.decode("utf-8").encode(" ...

  8. tcpdump命令(转载)

    https://www.cnblogs.com/ggjucheng/archive/2012/01/14/2322659.html 简介 用简单的话来定义tcpdump,就是:dump the tra ...

  9. centos6.9发送邮件功能

    centos6.9发送邮件功能       第一个里程碑 测试发邮件的功能 系统环境centos 6.9     #配置发邮件 /etc/mail.rc中追加 set bsdcompat set fr ...

  10. laraval一键安装包的下载地址

    http://laravelacademy.org/resources-download