▶ 书中第五章部分程序,包括在加上自己补充的代码,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. jQuery 常用操作

    jQuery操作: 不像dom是通过等号赋值,它是传递参数 $('#tb:checkbox').prop('checked'); 获取值 $('#tb:checkbox').prop('checked ...

  2. DOM 讲解

    DOM,全称documention,文档意思 ,就是把整个html文档当成一个对象来操作,里面有很多方法,如getElementByid(),getElementByid().innerText(); ...

  3. 运动目标检测中基于HSV空间的阴影去除算法

    在运动目标检测中,常常会出现由于光线被遮挡,或场景其他物体的遮挡,在目标附近或场景里出现阴影,阴影的出现对后期目标的正确分割与处理带了很大的不便.如今,国内外已有不少文献来研究这个问题,并且提出了各种 ...

  4. VMware Workstation 安装 mac OS 时遇到 不可恢复错误: (vcpu-0)

    去客户机的安装目录,打开VMX文件, 比如你的客户机名字为OSX, 这个文件就是OSX.vmx,你将会看到有一个smc.present的参数:smc.present = "TRUE" ...

  5. 深度图像配准(Registration)原理

    机器视觉中,3D相机产生的深度图像(depth image)通常需要配准(registration),以生成配准深度图像(registed depth image).实际上配准的目的就是想让深度图和彩 ...

  6. Windows系统下安装zip命令

    从GnuWin32 项目页面 上下载并安装 zip 命令 添加环境变量到系统中,即将安装目录添加至你的系统的 Path环境变量中( 假设安装目录时D:\Program Files (x86)\GnuW ...

  7. OpenStack 创建虚机过程简要汇总

    1. 总体流程 翻译自原文(英文):https://ilearnstack.com/2013/04/26/request-flow-for-provisioning-instance-in-opens ...

  8. Ajax的总结

    1.运行Ajax的环境,在服务器上才可以实现他的功能,客户端等别的地方,虽然也可以运行,但是功能一定是不全的,有可能很多东西都不会发生反应: 2.传参 (只写关键步骤)  (必须在服务器上运行) ge ...

  9. OpenVZ管理

    查找内存超过5%,CPU超过10% CPU=${:-} MEM=${:-} for CTID in `vzlist|sed '1d'|awk '{print $1}'` { echo "== ...

  10. CDN上的缓存刷新、缓存预热是怎样的使用场景?

    缓存刷新 源站内容更新后,希望用户可以获取到最新资源,CDN租户可以通过提交刷新请求将CDN节点上指定的缓存内容强制过期.当用户再次访问时,CDN节点将回源获取已更新内容返回给用户并在节点缓存最新资源 ...