代码过程:先用map计数文件字符频率,然后将字符与其频率存入一个节点,再将节点按频率顺序放入优先级队列,然后每次从队列取出2个构建一个树,再插入队列,反复进行直到队列中只有一个树为止,哈夫曼树就创建好了。
然后用一个递归的方法将每个字符与其对应二进制码存入map集合中,反向对应关系也存一个map方便解码,之后就比较简单了。
package TwoChildTree;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.HashMap;
import java.util.Map;
class Node1 {
Node1 left;
Node1 right;
int data;
char c;
public Node1(char c, int data) {//字符及对应频率
this.c = c;
this.data = data;
}
}
class Link {
Link next;
Node1 node;
public Link(Node1 node) {//存入节点
this.node = node;
}
}
public class HafumanTree {
static Link front;
static String s;
static HashMap<Character, Integer> map = new HashMap<>();
static void mapPut() {//统计各字符出现频率
for (char ch : s.toCharArray()) {
if (map.containsKey(ch))
map.put(ch, map.get(ch) + 1);
else {
map.put(ch, 1);
}
}
}
static void insert(Node1 node) {//链表的插入方法
Link link = new Link(node);
if (!isEmpty()) {
Link previous = front;
Link current = front;
while (node.data > current.node.data) {
previous = current;
current = current.next;
if (current == null) {
previous.next = link;
return;
}
}
if (current == front) {
link.next = front;
front = link;
return;
}
previous.next = link;
link.next = current;
} else
front = link;
}
static Node1 delete() {//链表删除方法
Node1 temp = front.node;
front = front.next;
return temp;
}
static boolean isEmpty() {
return (front == null);
}
static Node1 joinToTree() {//创建哈夫曼树
Node1 root = null;
while (!isEmpty()) {
Node1 n1 = delete();
Node1 n2 = delete();
root = new Node1('\0', n1.data + n2.data);
root.left = n1;
root.right = n2;
if (isEmpty())
break;
insert(root);
}
return root;
}
//取出字符与其对应二进制码
static void display(Node1 node, String str, Map<Character, String> m) {
if (node != null) {// 不能用while
if (node.left == null && node.right == null) {
char c = node.c;
m.put(c, str);
}
display(node.left, str + 0, m);
display(node.right, str + 1, m);
}
}
//解码
static void decode(Map<String, Character> m) {
try {
FileReader fr = new FileReader("D:\\2.txt");
FileWriter fw = new FileWriter("D:\\3.txt");
int i;
StringBuilder sb=new StringBuilder();
while ((i = fr.read()) != -1) {
sb.append((char)i);//问题在这里,要转为char
if(m.containsKey(sb.toString())){
fw.write(m.get(sb.toString()));
sb.delete(0, sb.capacity());
}
}
fw.close();
fr.close();
} catch (Exception e) {
e.printStackTrace();
}
}
//编码
static void encode(String str, Map<Character, String> m) {
StringBuilder sb = new StringBuilder();
for (char c : str.toCharArray())
sb.append(m.get(c));
try {
File file = new File("D:\\2.txt");
FileWriter fw = new FileWriter(file);
BufferedWriter br = new BufferedWriter(fw);
br.write(sb.toString());
br.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
File file = new File("D:\\1.txt");
try {
FileReader fr = new FileReader(file);
int i;
while ((i = fr.read()) != -1)
sb.append((char) i);
s = sb.toString();
fr.close();
} catch (Exception e) {
e.printStackTrace();
}
mapPut();
for (char c : map.keySet()) {
insert(new Node1(c, map.get(c)));
}
Node1 node = joinToTree();
String str = "";
HashMap<Character, String> m = new HashMap<>();
display(node, str, m);
HashMap<String, Character> m2 = new HashMap<>();
for (char c : m.keySet())
m2.put(m.get(c), c);
for (String ss : m2.keySet())
System.out.println(ss + " " + m2.get(ss));
encode(s, m);
decode(m2);
}
}