Java 霍夫曼编码(Huffman Coding)

本文介绍了使用Java实现霍夫曼编码的详细步骤,通过创建节点类存储权重、父节点和儿子节点信息,并利用旗标避免重复选取已用节点。在生成霍夫曼树后,不需遍历整树即可获取指定字符的编码,而是通过从目标节点向上查找父节点的路径得到编码。具体实现过程以代码形式展示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

霍夫曼编码的具体步骤如下

1)将信源符号的概率按减小的顺序排队。

2)把两个最小的概率相加,并继续这一步骤,始终将较高的概率分支放在右边,直到最后变成概率1。

3)画出由概率1处到每个信源符号的路径,顺序记下沿路径的0和1,所得就是该符号的霍夫曼码字。   

4)将每对组合的左边一个指定为0,右边一个指定为1(或相反)
  1. 思路:一个节点类包括权重,父亲左儿子,右儿子节点,flag 的false表示已经使用过了,下次找两个最小的不会再找这个false掉的了,parentPath表示儿子到父亲的路径上的数字,左边为0,右边为1(我这个里面设置了左边儿子比右边儿子小),存储哈夫曼节点;然后一个list存储刚输入的码的权重生成的节点,每次查找flag为true的两个最小的权重的节点,生成父节点,设置相关节点的属性值;最后输出编码,不用遍历树,直接找到要编码的码,然后一路向上查找parentPath的值就是编码的倒序,故采用栈来保存,最后输出编码就是正确的编码格式。
  2. 话不多说,上代码:
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);
		}
	}
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

八阿哥看招

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值