《算法》第六章部分程序 part 3
▶ 书中第六章部分程序,包括在加上自己补充的代码,后缀树的两种实现
● 后缀树实现一
package package01; import java.util.Arrays;
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut; public class class01
{
private Suffix[] suffixes; // 后缀数组 public class01(String text)
{
int n = text.length();
suffixes = new Suffix[n];
for (int i = 0; i < n; i++)
suffixes[i] = new Suffix(text, i);
Arrays.sort(suffixes);
} private static class Suffix implements Comparable<Suffix> // 后缀类,包含原字符串和该后缀在原字符串中的起始索引,text[0] = originText[index]
{ // 每个后缀元素都保存了原字符串,浪费
private final String text;
private final int index; private Suffix(String inputText, int inputIndex)
{
text = inputText;
index = inputIndex;
} private int length() // 求后缀元素的长度,要用原数组长度减去该后缀的起始索引
{
return text.length() - index;
} private char charAt(int i) // 取后缀元素的第 i 字符,要用起始索引开始数
{
return text.charAt(index + i);
} public int compareTo(Suffix that) // 比较两个后缀元素
{
if (this == that)
return 0;
int n = Math.min(this.length(), that.length());
for (int i = 0; i < n; i++)
{
if (this.charAt(i) < that.charAt(i))
return -1;
if (this.charAt(i) > that.charAt(i))
return +1;
}
return this.length() - that.length();
} public String toString()
{
return text.substring(index);
}
} public int length()
{
return suffixes.length;
} public int index(int i) // 注意 index 表示后缀元素的起始索引,同时也是各后缀元素的原始序号
{
if (i < 0 || i >= suffixes.length)
throw new IllegalArgumentException();
return suffixes[i].index;
} public int lcp(int i) // 计算排序的后缀数组中第 i 元素与第 i-1 元素的公共前缀长度
{
if (i < 1 || i >= suffixes.length)
throw new IllegalArgumentException();
Suffix s = suffixes[i], t = suffixes[i - 1];
int n = Math.min(s.length(), t.length());
for (int j = 0; j < n; j++)
{
if (s.charAt(j) != t.charAt(j))
return j;
}
return n;
} public String select(int i) // 返回排序后的后缀数组中第 i 元素
{
if (i < 0 || i >= suffixes.length)
throw new IllegalArgumentException();
return suffixes[i].toString();
} public int rank(String query) // 查找 query 在排序后的后缀数组中的排名
{
int lo = 0, hi = suffixes.length - 1;
for (; lo <= hi;)
{
int mid = lo + (hi - lo) / 2;
int cmp = compare(query, suffixes[mid]);
if (cmp < 0)
hi = mid - 1;
else if (cmp > 0)
lo = mid + 1;
else
return mid;
}
return lo;
} private static int compare(String query, Suffix suffix) // 比较两个后缀类
{
int n = Math.min(query.length(), suffix.length());
for (int i = 0; i < n; i++)
{
if (query.charAt(i) < suffix.charAt(i))
return -1;
if (query.charAt(i) > suffix.charAt(i))
return +1;
}
return query.length() - suffix.length();
} public static void main(String[] args)
{
String s = StdIn.readAll().replaceAll("\n", " ").trim();
class01 suffix = new class01(s); StdOut.println(" i ind lcp rnk select\n---------------------------");
for (int i = 0; i < s.length(); i++)
{
int index = suffix.index(i);
String ith = "\"" + s.substring(index, Math.min(index + 50, s.length())) + "\"";
assert s.substring(index).equals(suffix.select(i));
StdOut.printf("%3d %3d %3d %3d %s\n", i, index, (i == 0) ? 0 : suffix.lcp(i), suffix.rank(s.substring(index)), ith);
}
}
}
● 后缀树实现二
package package01; import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut; public class class01
{
private static final int CUTOFF = 5; // 插入排序分界 private final char[] text; // 原字符串,只保存一份
private final int[] index; // 索引数组,序后第 i 子串的首字符是原字符串中第 index[i] 字符
private final int n; // 字符串长度 public class01(String text)
{
n = text.length();
text += '\0';
text = text.toCharArray();
index = new int[n];
for (int i = 0; i < n; i++) // 初始化 index,排序交换是对 index 进行的
index[i] = i;
sort(0, n - 1, 0);
} private void sort(int lo, int hi, int d)// 基于字符串的第 d 位进行三路排序
{
if (hi <= lo + CUTOFF)
{
insertion(lo, hi, d);
return;
}
int lt = lo, gt = hi;
char v = text[index[lo] + d];
for (int i = lo + 1; i <= gt;) // 排序后 a[lo..lt-1] < v = a[lt..gt] < a[gt+1..hi]
{
char t = text[index[i] + d];
if (t < v)
exch(lt++, i++);
else if (t > v)
exch(i, gt--);
else
i++;
}
sort(lo, lt - 1, d); // 分别对前段,中段,后段进行排序
if (v > 0)
sort(lt, gt, d + 1);
sort(gt + 1, hi, d);
} private void insertion(int lo, int hi, int d)
{
for (int i = lo; i <= hi; i++)
{
for (int j = i; j > lo && less(index[j], index[j - 1], d); j--)
exch(j, j - 1);
}
} private boolean less(int i, int j, int d)// 比较
{
if (i == j)
return false;
for (i = i + d, j = j + d; i < n && j < n; i++, j++)
{
if (text[i] < text[j])
return true;
if (text[i] > text[j])
return false;
}
return i > j;
} private void exch(int i, int j)
{
int swap = index[i];
index[i] = index[j];
index[j] = swap;
} public int length()
{
return n;
} public int index(int i)
{
if (i < 0 || i >= n)
throw new IllegalArgumentException();
return index[i];
} public int lcp(int i)
{
if (i < 1 || i >= n)
throw new IllegalArgumentException();
int s = index[i], t = index[i - 1], n = 0;
for (; s < n && t < n; s++, t++, n++)
{
if (text[s] != text[t])
return j;
}
return n;
} public String select(int i)
{
if (i < 0 || i >= n)
throw new IllegalArgumentException();
return new String(text, index[i], n - index[i]);
} public int rank(String query)
{
int lo = 0, hi = n - 1;
for (; lo <= hi;)
{
int mid = lo + (hi - lo) / 2;
int cmp = compare(query, index[mid]);
if (cmp < 0)
hi = mid - 1;
else if (cmp > 0)
lo = mid + 1;
else
return mid;
}
return lo;
} private int compare(String query, int i)
{
int m = query.length(), j = 0;
for (; i < n && j < m; i++, j++)
{
if (query.charAt(j) != text[i])
return query.charAt(j) - text[i];
}
if (i < n)
return -1;
if (j < m)
return +1;
return 0;
} public static void main(String[] args)
{
String s = StdIn.readAll().replaceAll("\n", " ").trim();
class01 suffix = new class01(s); StdOut.println(" i ind lcp rnk select\n---------------------------");
for (int i = 0; i < s.length(); i++)
{
int index = suffix.index(i);
String ith = "\"" + s.substring(index, Math.min(index + 50, s.length())) + "\"";
assert s.substring(index).equals(suffix.select(i));
StdOut.printf("%3d %3d %3d %3d %s\n", i, index, (i == 0) ? 0 : suffix.lcp(i), suffix.rank(s.substring(index)), ith);
}
}
}
《算法》第六章部分程序 part 3的更多相关文章
- 《算法》第六章部分程序 part 7
▶ 书中第六章部分程序,加上自己补充的代码,包括全局最小切分 Stoer-Wagner 算法,最小权值二分图匹配 ● 全局最小切分 Stoer-Wagner 算法 package package01; ...
- 《算法》第六章部分程序 part 6
▶ 书中第六章部分程序,包括在加上自己补充的代码,包括二分图最大匹配(最小顶点覆盖)的交替路径算法和 HopcroftKarp 算法 ● 二分图最大匹配(最小顶点覆盖)的交替路径算法 package ...
- 《算法》第六章部分程序 part 5
▶ 书中第六章部分程序,包括在加上自己补充的代码,网络最大流 Ford - Fulkerson 算法,以及用到的流量边类和剩余流量网络类 ● 网络最大流 Ford - Fulkerson 算法 pac ...
- 《算法》第六章部分程序 part 8
▶ 书中第六章部分程序,加上自己补充的代码,包括单纯形法求解线性规划问题 ● 单纯形法求解线性规划问题 // 表上作业法,I 为单位阵,y 为对偶变量,z 为目标函数值 // n m 1 // ┌── ...
- 《算法》第六章部分程序 part 4
▶ 书中第六章部分程序,包括在加上自己补充的代码,利用后缀树查找最长重复子串.查找最大重复子串并输出其上下文(Key word in context,KWIC).求两字符串的最长公共子串 ● 利用后缀 ...
- 《算法》第六章部分程序 part 2
▶ 书中第六章部分程序,包括在加上自己补充的代码,B-树 ● B-树 package package01; import edu.princeton.cs.algs4.StdOut; public c ...
- 《算法》第六章部分程序 part 1
▶ 书中第六章部分程序,包括在加上自己补充的代码,粒子碰撞系统及用到的粒子类 ● 粒子系统 package package01; import java.awt.Color; import edu.p ...
- 《算法》第一章部分程序 part 1
▶ 书中第一章部分程序,加上自己补充的代码,包括若干种二分搜索,寻找图上连通分量数的两种算法 ● 代码,二分搜索 package package01; import java.util.Arrays; ...
- 《算法》第二章部分程序 part 5
▶ 书中第二章部分程序,加上自己补充的代码,包括利用优先队列进行多路归并和堆排序 ● 利用优先队列进行多路归并 package package01; import edu.princeton.cs.a ...
随机推荐
- MVC+linq开发经验
1.Though it is a mass,it will help you out of another mass,so,be glad to face it. 2.吃自己的狗粮.系统像一个房子,一 ...
- WASAPI、DirectSound/DS、WaveOut、Kernel Streaming/KS
先放结论: ASIO:硬件支持+对应驱动程序 DS:兼容性最好,一般也是默认的. WASAPI:是Vista之后的,较佳选择输出方式. 再来详细看: ASIO.WDM都是指音频通道,就是音频数据走的路 ...
- ALGO-9_蓝桥杯_算法训练_摆动序列(DP)
问题描述 如果一个序列满足下面的性质,我们就将它称为摆动序列: . 序列中的所有数都是不大于k的正整数: . 序列中至少有两个数. . 序列中的数两两不相等: . 如果第i – 1个数比第i – 2个 ...
- NGUI的数据绑定
ngui 的binding搜索结果 少之甚少 .即便去作者的youtube也收获不大 . 开发工作者更关心的是 数据的绑定,而不是一个显示控件简单属性的绑定. 说白了就是告诉用户 怎么绑定model吧 ...
- Python error: Microsoft Visual C++ 9.0 is required 解决方案
换了新电脑,在使用python2.7 pip 安装ipython时,报错了 error: Microsoft Visual C++ 9.0 is required. Get it from http: ...
- 服务链路追踪(Spring Cloud Sleuth)
sleuth:英 [slu:θ] 美 [sluθ] n.足迹,警犬,侦探vi.做侦探 微服务架构是一个分布式架构,它按业务划分服务单元,一个分布式系统往往有很多个服务单元.由于服务单元数量众多,业务的 ...
- 【ZZ】堆和堆的应用:堆排序和优先队列
堆和堆的应用:堆排序和优先队列 https://mp.weixin.qq.com/s/dM8IHEN95IvzQaUKH5zVXw 堆和堆的应用:堆排序和优先队列 2018-02-27 算法与数据结构 ...
- [转][PowerShell]ps执行重启IIS
来自:https://www.aliyun.com/jiaocheng/871477.html write-output 'Restarting IIS servers ............... ...
- webpack + vuejs(都是1.0的版本) 基本配置(一)
开始之前 本文包含以下技术,文中尽量给与详细的描述,并且附上参考链接,读者可以深入学习: 1.webpack12.Vue.js13.npm4.nodejs —- 这个就不给连接了,因为上面的连接都是在 ...
- 不同版本Eclipse对JDK版本要求
原文:https://blog.csdn.net/kevin_pso/article/details/54971739 1.Eclipse 4.6 (Neon)---需要JDK1.8版本,官网解释如下 ...