- 哈夫曼(Huffman)树创建及其带权路径长度(WPL)、哈夫曼编码、哈夫曼解码
package ccnu.offer.tree;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Stack;
public class Demo06 {
public static void test1(){
List<HuffmanNode> nodes = new ArrayList<HuffmanNode>();
nodes.add(new HuffmanNode("A", 40.0));
nodes.add(new HuffmanNode("B", 8.0));
nodes.add(new HuffmanNode("C", 10.0));
nodes.add(new HuffmanNode("D", 30.0));
nodes.add(new HuffmanNode("E", 10.0));
nodes.add(new HuffmanNode("F", 2.0));
HuffmanNode root = createHuffmanTree(nodes);
inOrder(root);
System.out.println();
System.out.println("WPL=" + getTreeWPL(root));
System.out.println(getLeavesPL(root, 0));
HashMap<String, String> h = getCharactersHuffmanEncoding(root);
Set<Entry<String, String>> entrys = h.entrySet();
for(Entry<String, String> entry : entrys){
System.out.println(entry.getKey() + ": " + entry.getValue());
}
System.out.println(textToNodesList("C:\\Users\\" + System.getenv("username") + "\\Desktop\\huffmanIn.txt"));
}
public static void test2(){
String src = "C:\\Users\\" + System.getenv("username") + "\\Desktop\\huffmanIn.txt";
String dest = "C:\\Users\\" + System.getenv("username") + "\\Desktop\\huffmanOut.txt";
String dest2 = "C:\\Users\\" + System.getenv("username") + "\\Desktop\\copyOfHuffmanIn.txt";
HuffmanNode root = createHuffmanTree(textToNodesList(src));
System.out.println("WPL=" + getTreeWPL(root));
getTextHuffmanEncoding(src, dest);
getTextHuffmanDecoding(getCharactersHuffmanEncoding(root), dest, dest2);
}
public static void main(String[] args) {
test1();
test2();
String src = "C:\\Users\\" + System.getenv("username") + "\\Desktop\\huffmanIn.txt";
System.out.println(textToNodesList(src));
}
public static HuffmanNode createHuffmanTree(List<HuffmanNode> f) {
if (f == null) {
return null;
}
if (f.size() == 0) {
return null;
}
while (f.size() > 1) {
f.sort(null);
HuffmanNode l = f.get(0);
HuffmanNode r = f.get(1);
HuffmanNode newNode = new HuffmanNode(l.data + r.data, l.weight + r.weight, l, r);
f.remove(0);
f.remove(0);
f.add(newNode);
}
return f.get(0);
}
public static HashMap<String, String> getCharactersHuffmanEncoding(HuffmanNode root){
return getCharactersHuffmanEncoding(root, "");
}
private static HashMap<String, String> getCharactersHuffmanEncoding(HuffmanNode root, String encoding){
Map<String, String> characterEncodingResultSet = new HashMap<String, String>();
if(root == null){
return null;
}
if(root.lchild == null && root.rchild == null){
characterEncodingResultSet.put(root.data, encoding);
}else{
characterEncodingResultSet.putAll(getCharactersHuffmanEncoding(root.lchild, encoding + "0"));
characterEncodingResultSet.putAll(getCharactersHuffmanEncoding(root.rchild, encoding + "1"));
}
return (HashMap<String, String>)characterEncodingResultSet;
}
public static ArrayList<HuffmanNode> textToNodesList(String pathname) {
if (pathname == null || pathname.length() == 0) {
return null;
}
ArrayList<HuffmanNode> huffmanNodes = new ArrayList<HuffmanNode>();
HashMap<String, Double> dwMap = new HashMap<String, Double>();
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(pathname))));
char ch;
while (true) {
int i = br.read();
if (i == -1) {
break;
} else {
ch = (char) i;
}
double count = 1;
if (dwMap.containsKey(String.valueOf(ch))) {
count = dwMap.get(String.valueOf(ch)) + 1;
}
dwMap.put(String.valueOf(ch), count);
}
br.close();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Set<Entry<String, Double>> entrys = dwMap.entrySet();
for (Entry<String, Double> entry : entrys) {
huffmanNodes.add(new HuffmanNode(entry.getKey(), entry.getValue()));
}
return huffmanNodes;
}
public static void getTextHuffmanEncoding(String textSrc, String textDest) {
if (textSrc == null || textDest == null) {
return;
}
ArrayList<HuffmanNode> huffmanNodes = textToNodesList(textSrc);
HuffmanNode root = createHuffmanTree(huffmanNodes);
HashMap<String, String> characterEncodingResultSet = getCharactersHuffmanEncoding(root);
BufferedReader br = null;
BufferedWriter bw = null;
try {
br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(textSrc))));
bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(textDest))));
char ch;
while (true) {
int i = br.read();
if (i == -1) {
break;
} else {
ch = (char) i;
}
String characterEncoding = characterEncodingResultSet.get(String.valueOf(ch));
bw.write(characterEncoding);
}
bw.flush();
bw.close();
br.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void getTextHuffmanDecoding(Map<String, String> decoder, String textSrc, String textDest){
if(textSrc == null || textDest == null){
return;
}
BufferedReader br = null;
BufferedWriter bw = null;
String tmp = "";
try {
br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(textSrc))));
bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(textDest))));
while(true){
int i = br.read();
if(-1 == i){
break;
}else{
tmp += (char)i;
}
if(decoder.containsValue(tmp)){
String data = getKeysByValue(decoder, tmp)[0];
if(data.equals("")){
bw.write("\n\r");
}else{
bw.write(data);
}
tmp = "";
}
}
bw.flush();
bw.close();
br.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static String[] getKeysByValue(Map map, String value) {
StringBuffer sb = new StringBuffer();
Set<Entry<String, String>> entrys = map.entrySet();
Iterator<Map.Entry<String, String>> iter = entrys.iterator();
while(iter.hasNext()){
Map.Entry<String, String> entry = iter.next();
String value2 = entry.getValue();
if(value2 != null && value2.equals(value)){
sb.append(entry.getKey() + " ");
}
}
String keys = sb.toString().trim();
return keys.split(" +");
}
public static void inOrder(HuffmanNode root){
if(root != null){
inOrder(root.lchild);
if(root.lchild == null && root.rchild == null){
System.out.print(root.data + " ");
}
inOrder(root.rchild);
}
}
public static double getTreeWPL(HuffmanNode root){
Stack<HuffmanNode> nodes = new Stack<HuffmanNode>();
double WPL = 0;
while(root != null || !nodes.isEmpty()){
if(root != null){
nodes.push(root);
root = root.lchild;
}else{
root = nodes.peek();
if(root.tag){
nodes.pop();
root = null;
}else{
root.tag = true;
if(root.lchild == null && root.rchild == null){
WPL += (nodes.size() - 1) * root.weight;
}
root = root.rchild;
}
}
}
return WPL;
}
public static ArrayList<Integer> getLeavesPL(HuffmanNode root, int depth) {
ArrayList<Integer> pls = new ArrayList<Integer>();
if (root == null) {
return null;
}
if (root.lchild == null && root.rchild == null) {
pls.add(depth);
return pls;
} else {
pls.addAll(getLeavesPL(root.lchild, depth + 1));
pls.addAll(getLeavesPL(root.rchild, depth + 1));
}
return pls;
}
private static class HuffmanNode implements Comparable<HuffmanNode> {
private String data;
private double weight;
private HuffmanNode lchild;
private HuffmanNode rchild;
private boolean tag;
public HuffmanNode(String data, double weight) {
this(data, weight, null, null);
}
public HuffmanNode(String data, double weight, HuffmanNode lchild, HuffmanNode rchild){
this.data = data;
this.weight = weight;
this.lchild = lchild;
this.rchild = rchild;
}
@Override
public int compareTo(HuffmanNode o) {
if (o == null) {
return 0;
}
if (this.weight > o.weight) {
return 1;
} else if (this.weight == o.weight) {
return 0;
} else {
return -1;
}
}
@Override
public String toString() {
return data + "=" + weight;
}
}
}