哈夫曼树--链式结构(建立huffman树、编码、解码)

时间:2021-07-04 11:30:15
引子: 用链式结构来建立哈夫曼树。 总体思路是: 将每一棵树(这是每一棵树只有一个节点,头节点)放在一个优先队列中(下面的是链表实现的优先队列),频率(rate)小的在队列头,取出队列头两个,频率相加之后组合成一个有三个节点的树,重新放入优先队列中。重复上面的过程,直到最后只剩下一个,则这最后一个便是哈夫曼树。 编码:从叶子节点开始往上。 解码:从根节点开始往下。

package tree;

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;

/**
* 哈夫曼编码解码
* @author LiangYH
*
*/
public class HuffmanTest {

public static void main(String[] args) {
HuffmanTest tree1 = new HuffmanTest();
tree1.setRoot("A", 9);

HuffmanTest tree2 = new HuffmanTest();
tree2.setRoot("B", 5);

HuffmanTest tree3 = new HuffmanTest();
tree3.setRoot("C", 8);
HuffmanTest tree4 = new HuffmanTest();
tree4.setRoot("E", 19);
HuffmanTest tree7 = new HuffmanTest();
tree7.setRoot("F", 11);


MyLink link = new MyLink();
link.add(tree1);
link.add(tree2);
link.add(tree3);
link.add(tree7);
link.add(tree4);
link.printLink();

HuffmanTest t1 = null;
HuffmanTest t2 = null;
while(link.size() > 1){
t1 = link.delete();
t2 = link.delete();
t2.growTree(t1);
link.add(t2);
}

t2.printTree();

Map<String,List<String>> map = t2.getCodeTable();

t2.printCodeTable(map);

List<String> list = t2.encode("AEBCF");

List<String> li2 = t2.decode(list);

System.out.println();
System.out.print("解码: ");
for(String s: li2){
System.out.print(s);
}
}

private List<Node> leaves = null;
private Map<String, List<String>> codeMap= null;

private Node root = null;


public HuffmanTest(){
leaves = new ArrayList<Node>();
codeMap = new HashMap<String, List<String>>();
}

public Map<String,List<String>> getCodeMap(){
return this.codeMap;
}

public List<Node> getLeaves(){
getLeaves(root);
return this.leaves;
}

public void setRoot(String item, int rate){
this.root = new Node(item, rate);
}

public Node getRoot(){
return this.root;
}

public int getRateOfRoot(){
return this.root.rate;
}

public void growTree(HuffmanTest newTree){
Node newNode = new Node();
//设置子节点
newNode.leftChild = this.root;
newNode.rightChild = newTree.getRoot();
//设置父节点
this.root.parent = newNode;
newTree.getRoot().parent = newNode;
//设置父节点的权重
newNode.setRate(this.root.rate+newTree.getRateOfRoot());
//重置根节点
this.root = newNode;
}

public void InOrderTraverse(HuffmanTest tree){
traverse(tree.root);

}

private void traverse(Node node){
if(node != null){
System.out.print(node.item+"/"+node.rate+"; ");
traverse(node.leftChild);
traverse(node.rightChild);
}
}

//获取叶子节点
private void getLeaves(Node node){
if(node != null){
if(node.item != null){
leaves.add(node);
}
getLeaves(node.leftChild);

getLeaves(node.rightChild);
}
}

public Map<String,List<String>> getCodeTable(){
//获取叶子节点
getLeaves(root);
int len = leaves.size();
for(int i = 0; i < len; i++){
Node tempNode = leaves.get(i);
List<String> tempList = new ArrayList<String>();

codeMap.put(tempNode.item, tempList);

while(tempNode.parent != null){
if(tempNode == tempNode.parent.leftChild){
tempList.add("0");
}else if(tempNode == tempNode.parent.rightChild){
tempList.add("1");
}
tempNode = tempNode.parent;
}
}

return this.codeMap;
}

public List<String> encode(String target){
System.out.println();
System.out.print(target+" 的编码: ");

List<String> li = new ArrayList<String>();

int len = target.length();
for(int i = 0; i < len; i++){
String temp = String.valueOf(target.charAt(i));
List<String> list = codeMap.get(temp);
for(int k = list.size()-1; k >= 0; k--){
System.out.print(list.get(k));
li.add(list.get(k));
}
}
return li;
}

/**
* 解码
* @param codeList 二进制编码
* @return 解码结果
*/
public List<String> decode(List<String> codeList){

List<String> list = new ArrayList<String>();

Node tempNode = null;
tempNode = root;
for(String s: codeList){
if("0".equals(s)){
tempNode = tempNode.leftChild;
if(tempNode.item != null){
list.add(tempNode.item);
tempNode = root;
continue;
}
}else if("1".equals(s)){
tempNode = tempNode.rightChild;
if(tempNode.item != null){
list.add(tempNode.item);
tempNode = root;
continue;
}
}
}
return list;
}

public void printTree(){
InOrderTraverse(this);
}

public void printCodeTable(Map<String,List<String>> codeTable){
Set<Entry<String,List<String>>> set = codeTable.entrySet();
Iterator<Entry<String,List<String>>> iter = set.iterator();
System.out.println();
while(iter.hasNext()){
Entry<String,List<String>> entry = iter.next();
System.out.print(entry.getKey()+": ");

List<String> li = entry.getValue();
for(int i = li.size()-1; i >= 0; i--){
System.out.print(li.get(i));

}
System.out.print("; ");
}
}

class Node{
Node leftChild = null;
Node rightChild = null;
Node parent = null;
//字母
String item = null;
//字母出现的频率
int rate = 0;

public Node(){

}
public Node(String item, int rate){
this.item = item;
this.rate = rate;
}

public void setItem(String item){
this.item = item;
}

public void setRate(int rate){
this.rate = rate;
}

public void printNode(){
System.out.println(item+"\\"+rate+"; ");
}
}
}

/**
* 优先链表
* @author LiangYH
*
*/
class MyLink{

private LinkNode first = null;
private int size = 0;


public MyLink(){

}

/**
* 增加节点,并按照相关顺序从小到大排列
* @param tree
*/
public void add(HuffmanTest tree){
LinkNode newNode = new LinkNode(tree);


if(first == null){
first = newNode;
size++;
}else{
boolean isNextNull = false;
LinkNode previous = first;
LinkNode temp = first;
while(tree.getRateOfRoot() > temp.tree.getRateOfRoot()){
if(temp.next == null){
isNextNull = true;
break;
}
previous = temp;
temp = temp.next;
}

//temp所指的是最后一个
if(isNextNull){
temp.next = newNode;
size++;
return;
}
//如果temp指向的是第一个
if(temp == first){
newNode.next = first;
first = newNode;
size++;
}else{
newNode.next = temp;
previous.next = newNode;
size++;
}

}
}

/**
* 删除最左边的一个元素
* @return
*/
public HuffmanTest delete(){
if(isEmpty())
return null;

LinkNode temp = first;
first = first.next;

size--;
return temp.tree;
}

public boolean isEmpty(){
return first == null;
}

public int size(){
return this.size;
}

public void printLink(){
LinkNode temp = first;
while(temp.next != null){
System.out.print(temp.tree.getRoot().item+"\\"+temp.tree.getRateOfRoot()+"; ");
temp = temp.next;
}
System.out.println(temp.tree.getRoot().item+"\\"+temp.tree.getRateOfRoot());
}

/**
* 内部类
* @author LiangYH
*
*/
class LinkNode{
LinkNode next = null;
HuffmanTest tree;

public LinkNode(HuffmanTest tree){
this.tree = tree;
}
}

}