霍夫曼编码的具体步骤如下
1)将信源符号的概率按减小的顺序排队。
2)把两个最小的概率相加,并继续这一步骤,始终将较高的概率分支放在右边,直到最后变成概率1。
3)画出由概率1处到每个信源符号的路径,顺序记下沿路径的0和1,所得就是该符号的霍夫曼码字。
4)将每对组合的左边一个指定为0,右边一个指定为1(或相反)
- 思路:一个节点类包括权重,父亲左儿子,右儿子节点,flag 的false表示已经使用过了,下次找两个最小的不会再找这个false掉的了,parentPath表示儿子到父亲的路径上的数字,左边为0,右边为1(我这个里面设置了左边儿子比右边儿子小),存储哈夫曼节点;然后一个list存储刚输入的码的权重生成的节点,每次查找flag为true的两个最小的权重的节点,生成父节点,设置相关节点的属性值;最后输出编码,不用遍历树,直接找到要编码的码,然后一路向上查找parentPath的值就是编码的倒序,故采用栈来保存,最后输出编码就是正确的编码格式。
- 话不多说,上代码:
package com.leibobo;
/**
* Created by bobolei 18/4/13
*哈夫曼节点定义
*/
public class NodeHuffman {
//权重,标志位,父节点,左右儿子
//flag = false表示还没有进行合并,即还是一个没有归类的节点
//创建树的过程中直接标记哈夫曼编码,根节点父路劲为-1,其他父路径自己是左儿子,则为0,右儿子,则为1,后面直接找到要编码的数,向上查找即是哈夫曼编码的反路劲,翻转即可。。。哈哈哈哈,我号机智
private int weight;
private boolean flag; //默认false
private int parentPath; //默认是0
public int getParentPath() {
return parentPath;
}
public void setParentPath(int parentPath) {
this.parentPath = parentPath;
}
private NodeHuffman parent,lChild,rChild;
public NodeHuffman(){
}
public NodeHuffman(int weight){
this.weight = weight;
flag = true;
parent = lChild = rChild = null;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public NodeHuffman getParent() {
return parent;
}
public void setParent(NodeHuffman parent) {
this.parent = parent;
}
public NodeHuffman getlChild() {
return lChild;
}
public void setlChild(NodeHuffman lChild) {
this.lChild = lChild;
}
public NodeHuffman getrChild() {
return rChild;
}
public void setrChild(NodeHuffman rChild) {
this.rChild = rChild;
}
}
package com.leibobo;
import java.util.List;
/**
* Created by bobolei 18/4/13
*哈夫曼节点定义
*/
public class SelectTwoMin {
//获取节点list中权重最小的两个,并返回,0,1大
public NodeHuffman[] getMinTwo(List<NodeHuffman> listHuffman){
NodeHuffman big = null;
NodeHuffman small = null;
for(int i = 0;i < listHuffman.size();i++){
if(listHuffman.get(i).isFlag()){
if(small == null){
small = listHuffman.get(i);
continue;
}
if(small != null && big == null){
if(small.getWeight() > listHuffman.get(i).getWeight()){
big = small;
small = listHuffman.get(i);
}else{
big = listHuffman.get(i);
}
continue;
}
if(small != null && big != null){
if(listHuffman.get(i).getWeight() < big.getWeight() && listHuffman.get(i).getWeight() > small.getWeight()){
big = listHuffman.get(i);
}
if(listHuffman.get(i).getWeight() < small.getWeight()){
big = small;
small = listHuffman.get(i);
}
}
}else{
continue;
}
}
NodeHuffman[] minTwoHuffman = {small,big};
return minTwoHuffman;
}
}
package com.leibobo;
import java.util.ArrayList;
import java.util.List;
/**
* Created by bobolei 18/4/13
*哈夫曼节点定义
*/
public class TreeHuffman {
public List<NodeHuffman> getHuffmanTreeList(int[] weight,List<NodeHuffman> huffmanTreeList){
int m=2*weight.length-1;
//生成原始的Huffman节点
for(int i = 0;i < weight.length;i++){
NodeHuffman nodeHuffman = new NodeHuffman(weight[i]);
huffmanTreeList.add(nodeHuffman);
}
SelectTwoMin selectTwoMin = new SelectTwoMin();
for(int j = weight.length;j < m;j++){
NodeHuffman[] minTwoHuffman = selectTwoMin.getMinTwo(huffmanTreeList);
System.out.println("最小的两个:"+minTwoHuffman[0].getWeight()+" "+minTwoHuffman[1].getWeight());
minTwoHuffman[0].setFlag(false);
minTwoHuffman[0].setParentPath(0);
minTwoHuffman[1].setFlag(false);
minTwoHuffman[1].setParentPath(1);
NodeHuffman newNode = new NodeHuffman();
newNode.setFlag(true);
newNode.setlChild(minTwoHuffman[0]);
newNode.setrChild(minTwoHuffman[1]);
newNode.setWeight(minTwoHuffman[0].getWeight()+minTwoHuffman[1].getWeight());
newNode.setParentPath(-1);
newNode.setParent(null);
huffmanTreeList.add(newNode);
minTwoHuffman[0].setParent(huffmanTreeList.get(j));
minTwoHuffman[1].setParent(huffmanTreeList.get(j));
}
return huffmanTreeList;
}
}
package com.leibobo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Stack;
/**
* Created by bobolei 18/4/13
*哈夫曼节点定义
*/
//java中方法传递的只是引用,不是对象,即一个对象通过方法操作返回的还是这个对象,只不过两个地方是不同的引用而已
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
System.out.println("输入编码的字符:");
String code = sc.nextLine();
System.out.println("请输入以此对应的次数:");
String[] nums = null;
nums = sc.nextLine().split(" ");
int inputInt[]=new int[nums.length];
for(int i=0;i<inputInt.length;i++){
inputInt[i]=Integer.valueOf(nums[i]);
}
for(int j = 0;j < inputInt.length;j++){
System.out.print(inputInt[j]+" ");
}
System.out.println(" ");
//int[] inputInt={23,11,5,3,29,14,7,8};
//int[] inputInt={12,6,2,18};
System.out.println("输出:");
Map<Integer,Stack<Integer>> map = new HashMap<Integer,Stack<Integer>>();
List<NodeHuffman> huffmanTreeList = new ArrayList<NodeHuffman>();
TreeHuffman treeHuffman = new TreeHuffman();
treeHuffman.getHuffmanTreeList(inputInt, huffmanTreeList);
for(int j = 0;j < inputInt.length;j++){
boolean mark = true;
Stack<Integer> stack = new Stack<Integer>();
NodeHuffman node = huffmanTreeList.get(j);
System.out.print("code:"+code.charAt(j)+" 权重:"+huffmanTreeList.get(j).getWeight() + "编码 :");
while(mark){
if(node.getParentPath() != -1){
System.out.print(node.getParentPath());
stack.push(node.getParentPath());
node = node.getParent();
}else{
mark = false;
}
}
System.out.println(" ");
map.put(huffmanTreeList.get(j).getWeight(), stack);
}
}
}