关于字符串的一些算法的github
https://github.com/fuzekun/MyAlgorithm
使用IDEA写的,jdk8.0以及以上就可运行,就是写算法的,用不到其他的外部依赖
用图片说话
流程
<一>编码实现
1.建立哈夫曼树
(1)统计叶子节点(每个字符)的权重
(2)初始化优先队列
(3)依次找到队列中最小和次小的节点,创建新节点作为这两个节点父节点,权重为两个父节点的和,然后放入有限队列中,直到队列中还有一个节点,这个就是根节点
2.建立编码表
(1)递归前序遍历哈夫曼树
(2)左子树编码为0,右子树编码为1
(3)如果是叶子节点,使用映射保存叶子节点字符的编码。
3.将树保存为比特流
(1)递归的前序遍历树,如果是叶子节点,保存标志1,并且将叶子对应的字符保存为八位2进制,返回
(2)如果不是叶子节点,保存标志0
4…实现字符串编码
再次遍历一遍输入流,从映射中找到每个字符对应的哈夫曼编码,保存下来
<二>解码实现
1.读取汉夫曼树
(1)递归前序遍历树,如果是叶子节点,放回一个新的叶子节点(没有左右子树)
(2)否则返回一个新的根节点(左右子树递归遍历比特流)
2.将编码通过树解码
遍历剩下的比特流(字符串的编码),根据得到的哈夫曼树,得到具体的字符
如果是叶子节点,输出字符
否规是0遍历左子树,是1遍历右子树
实现
用到了优先队列具体的代码在github中,这里只有哈夫曼的代码,如果想完整的运行,请下载我github中代码,不用配置直接运行。
package 字符串;
import dataStructure.MinPQ;
import java.io.*;
import java.util.ArrayList;
//哈夫曼编码实现数据压缩
public class Huffman {
private static int R = 256; //字母表的大小,2^8
private static String file = ""; //写入文件的内容,为哈夫曼编码
private static String tree = ""; //二进制的哈夫曼树
private static ArrayList<String> codings = new ArrayList<>();//字符的编码
private static int pos = -1; //读取编码树时候所需要的位置信息
private static class Node implements Comparable<Node>{
private char ch;
private int freq;
private final Node left,right;
public Node(char ch,int freq,Node left,Node right){
this.ch = ch;
this.freq = freq;
this.left = left;
this.right = right;
}
public boolean isleaf(){
return left == null && right == null;
}
public int compareTo(Node other){
return this.freq - other.freq;
}
}
//扩展编码,还原原来的字符串
public static void expand(){
char[] filen = file.toCharArray();
System.out.println("读取树:");
Node root = readTrie(tree.toCharArray());
System.out.println();
int i = tree.length();
String ans = "";
while( i < filen.length){
Node x = root;
while(!x.isleaf()){
if(filen[i++] == '0'){
x = x.left;
}
else x = x.right;
}
ans += x.ch;
System.out.print(x.ch);
}
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(new File("hufen.txt")));
writer.write(ans);
writer.close();
}catch (Exception e){
System.out.println(e.getMessage());
}
}
//编码
public static String[] buildCode(Node root){
//使用单词查找树构造编译表
String[] st = new String[R];
buildCode(st,root,"");
return st;
}
public static void buildCode(String[] st,Node x,String s){
//使用单词查找树构造编译表
if(x.isleaf()){
st[x.ch] = s;return ;
}
buildCode(st,x.left,s + '0');
buildCode(st,x.right,s + '1');
}
//打印编译树
public static void printTree(Node root){
if(root.isleaf()){
System.out.println(root.ch);
return ;
}
printTree(root.left);
printTree(root.right);
}
//建立编译树
private static Node buildTrie(int[] freq){
//使用多棵单节点树初始化优先队列
MinPQ<Node>pq = new MinPQ<>(100);
for(char c = 0; c < R; c++){
if(freq[c] > 0){
pq.insert(new Node(c,freq[c],null,null));
}
}
// for(Node node : pq){
// System.out.println(node.ch);
// }
while(pq.size() > 1){
Node x = pq.delMin();
Node y = pq.delMin();
Node parent = new Node('\0',x.freq + y.freq, x, y);
pq.insert(parent);
}
Node root = pq.delMin();
return root;
}
//将编译树转化成比特流
private static void writeTrie(Node x){
if(x.isleaf()){
//1.叶子节点写1加上8位ascii码
tree += '1';
String tmp = Integer.toBinaryString((int)x.ch);
//转换成ASCII码,八位
for(int i = tmp.length(); i < 8; i++){
tmp = '0' + tmp;
}
tree += tmp;
return;
}
//2.非叶子节点写0
tree += '0';
//3.递归建立
writeTrie(x.left);
writeTrie(x.right);
}
//读取编译树
private static Node readTrie(char[] file){
pos++;
//从文件中读入字符串
if(file[pos] == '1'){//叶子节点
System.out.print(1);
int x = 0;
for(int i = 0; i < 8; i++){
x = x * 2 + file[++pos] - '0';
System.out.print(file[pos]);
}
System.out.print(" ");
return new Node((char)x,0,null,null);
}
System.out.print(file[pos]);
return new Node('\0',0,readTrie(file),readTrie(file));
}
//压缩
public static void compress(String s) {
char[] input = s.toCharArray();
//1.统计频率
int[] freq = new int[R];
for(int i = 0; i < input.length; i++){
freq[input[i]]++;
}
//2.构造霍夫曼编码树
Node root = buildTrie(freq);
//3.构造编译表
String[] st ;
st = buildCode(root);
//4.打印解码用的单词查找树
writeTrie(root);
// //5.打印字符总数
// int n = input.length;
// file += Integer.toBinaryString(n);
//必要的打印,帮助理解
System.out.println("单词查找树为");
System.out.println(tree);
System.out.println("各个字符的编码是:");
for(int i = 0; i < st.length; i++){
if(st[i] != null && st[i].compareTo("") != 0)System.out.println((char)i + " : " + st[i]);
}
System.out.println("字符串的编码是:");
//使用霍夫曼编码处理输入
for(int i = 0; i < input.length; i++){
String code = st[input[i]];
System.out.print(code);
codings.add(code);
}
System.out.println();
System.out.println("哈夫曼编码是:");
file = tree;
for(String stt : codings){
file += stt;
}
System.out.println(file);
//6.将编码写入文件
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(new File("huf.txt")));
writer.write(file);
writer.close();
}catch (Exception e){
System.out.println(e.getMessage());
}
}
public static void main(String[] args) {
// Huffman huffman = new Huffman();
// huffman.compress("ABRACADABRA!");
// huffman.expand();
Huffman.compress("I am happy today");
System.out.println("解码是:");
Huffman.expand();
}
}
性能分析
(1)适用于给定的字符串,对于任意长度的字符串无法处理。
(2)字符串的中字符的重复越多,性能越好,字符
(3)字符数组的