赫夫曼编码的Java实现

    上次egg写了一个赫夫曼算法的java实现,我在此也把自己的劣作搬上来让高人指点,
其实这是我们老师布置的一个作业,后来发现本班大部分男生竟然抄袭女生的代码,并且

也交了差,实让我愤怒,为了给男同胞们争口气,我决定自己写一个,也算是对得住自己
了!

     程序描述 :赫夫曼算法一般用于数据压缩,应用于远程通信中可以减少数据流量,从而保持比较好的传输速度。下面的程序实现的功能是:从外部传进一个字符串对象,程序根据
该字符串构造赫夫曼编码。例如:字符串s="我我我 是 一 个贼贼aaaaa",该字符串
有3个空格,其赫夫曼编码的一种如下:
个:01101
 :00
我:10
a:11
是:0101
一:11101
贼:001

构造出来的赫夫曼树的结构如下:
第0个:【叶节点值:3;父节点值:6】
第1个:【叶节点值:3;父节点值:6】
第2个:【叶节点值:1;父节点值:3】
第3个:【叶节点值:1;父节点值:2】
第4个:【叶节点值:1;父节点值:2】
第5个:【叶节点值:2;父节点值:5】
第6个:【叶节点值:5;父节点值:10】
第7个:【节点值:2;父节点值:3;左孩子:1;右孩子:1】
第8个:【节点值:3;父节点值:5;左孩子:1;右孩子:2】
第9个:【节点值:5;父节点值:10;左孩子:2;右孩子:3】
第10个:【节点值:6;父节点值:16;左孩子:3;右孩子:3】
第11个:【节点值:10;父节点值:16;左孩子:5;右孩子:5】
第12个:【根节点值:16;左孩子:6;右孩子:10】

1,定义赫夫曼树节点class

package cn.hunnu.huffman;

/**
 * 赫夫曼节点类
 * @author: 肖波
 *
 */
public class HuffmanNode {
	private int weight=0;//结点权值
	private HuffmanNode parent=null;//父节点
	private HuffmanNode lchild=null;//左孩子
	private HuffmanNode rchild=null;//右孩子

	public int getWeight() {
		return weight;
	}

	public void setWeight(int weight) {
		this.weight = weight;
	}

	public HuffmanNode getParent() {
		return parent;
	}

	public void setParent(HuffmanNode parent) {
		this.parent = parent;
	}

	public HuffmanNode getLchild() {
		return lchild;
	}

	public void setLchild(HuffmanNode lchild) {
		this.lchild = lchild;
	}

	public HuffmanNode getRchild() {
		return rchild;
	}

	public void setRchild(HuffmanNode rchild) {
		this.rchild = rchild;
	}
	
	public String toString(){
		if(parent==null){
			return "【根节点值:"+weight+";左孩子:"+
		       lchild.getWeight()+";右孩子:"+rchild.getWeight()+"】";
		}
		else if(lchild==null&&rchild==null){
			return "【叶节点值:"+weight+";父节点值:"+parent.getWeight()+"】";
		}else
		return "【节点值:"+weight+";父节点值:"+parent.getWeight()+";左孩子:"+
		       lchild.getWeight()+";右孩子:"+rchild.getWeight()+"】";
	}
}

 

   2,赫夫曼树

package cn.hunnu.huffman;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * 赫夫曼树定义
 * @author: 肖波
 *
 */
public class HuffmanTree {
	private List<HuffmanNode> htree;//用于存放赫夫曼节点的列表
	private Map<Character,HuffmanNode> charMap;//一个字符对应一个赫夫曼结点的映射对象。
	
	/**
	 * 根据传入得字符串参数构造赫夫曼树
	 * @param str
	 */
	public HuffmanTree(String str){
		htree = new ArrayList<HuffmanNode>();
		//构造字符队列,用于存放所有的字符。
		List<Character> charList = new ArrayList<Character>();
		for(int i = 0;i<str.length();i++){
			charList.add(str.charAt(i));
		}
		//构造一个映射,用于存放字符及其赫夫曼节点。
		charMap = new HashMap<Character,HuffmanNode>();
		while(charList.size()>0){//初始化charMap对象和htree叶节点
			int count = 0;
			for(int k = 0;k<charList.size();k++){
				if(charList.get(0).equals(charList.get(k))){
					count++;
					if(k>0){
						charList.remove(k);
						k--;
				    }
			    }
		    }
			HuffmanNode node = new HuffmanNode();//创建叶节点
			node.setWeight(count);
		    charMap.put(charList.remove(0),node);
		    htree.add(node);
	   }

		if(charMap.size()<2){//如果只传进一个字符,则不能构成赫夫曼树。
			System.out.println("不构成赫夫曼树的条件!");
			return ;
		}

	   //非叶节点赋值
	   for(int i = 0;i<(charMap.size()-1);i++){
		   HuffmanNode parent = new HuffmanNode();
		   //选出权值最小的一个节点
		   HuffmanNode min1 = htree.get(htree.size()-1);
		   for(int j = 0;j<htree.size();j++){
			   if((null==htree.get(j).getParent())&&
					   htree.get(j).getWeight()<=min1.getWeight()){
				   min1 = htree.get(j);
			   }
		   }
		   min1.setParent(parent);
		   parent.setLchild(min1);
		   
		   //选出权值次于最小权值的节点
		   HuffmanNode min2 = null;
		   for(int j = 0;;j++){
			   if(null==htree.get(j).getParent()){
				   min2 = htree.get(j);//用于比较大小的参照物
				   break;
			   }
		   }
		   
		   for(int j = 0;j<htree.size();j++){
			   if(htree.get(j).getParent()==null&&
					   (htree.get(j).getWeight()<=min2.getWeight())){
				   min2 = htree.get(j);
			   }
		   }
		   min2.setParent(parent);
		   parent.setRchild(min2);
		   parent.setWeight(min1.getWeight()+min2.getWeight());
		   htree.add(parent);
	   }
	}
	
	/**
	 * 获取赫夫曼树
	 * @return
	 */
	public HuffmanTree getHuffmanTree(){
		return this;
	}

	/**
	 * 获得赫夫曼编码,
	 * 例如:	a:00
	 * 		b:10
	 * 		e:1
	 * @return 赫夫曼树的全部赫夫曼编码,以字符串的形式表示。
	 */
	public String getHuffmanCode(){
		if(null==htree){//如果赫夫曼树为空,返回null。
			return null;
		}
		StringBuffer stbu = new StringBuffer();
		Iterator<Character> it = charMap.keySet().iterator();
		while(it.hasNext()){
			Character c = it.next().charValue();
			HuffmanNode node = charMap.get(c);
			stbu.append(c+":"+getHuffmanNodeCode(node)+"\r\n");
		}
		return stbu.toString();
	}
	
	/**
	 * 获得指定节点的赫夫曼编码
	 * @param node 赫夫曼节点
	 * @return 节点的赫夫曼编码
	 */
	public String getHuffmanNodeCode(HuffmanNode node){
		String code = "";
		if(null==node.getParent()){
			return code;
		}
		if(node.equals(node.getParent().getLchild())){
			//是父节点的左孩子
			code = "0"+getHuffmanNodeCode(node.getParent());
		}
		else if(node.equals(node.getParent().getRchild())){
			//是右孩子
			code = "1"+getHuffmanNodeCode(node.getParent());
		}
		return code;
	}
	
	public List<HuffmanNode> getHtree() {
		return htree;
	}

	public void setHtree(List<HuffmanNode> htree) {
		this.htree = htree;
	}

	public Map<Character, HuffmanNode> getCharMap() {
		return charMap;
	}
	/**
	 * 赫夫曼树结构图:字符串表示。
	 */
	public String toString(){
		StringBuffer strb = new StringBuffer("");
		for(int i = 0;i<htree.size();i++){
		   strb.append("第"+i+"个:"+htree.get(i)+"\n");
		}
		return strb.toString();
	}
}
 

 

3,测试类

import cn.hunnu.huffman.HuffmanTree;


public class TestString {
        public static void main(String args[]){
	 HuffmanTree ht = new HuffmanTree("aabbb cccc我我是 ");

	 System.out.println(ht);//输出赫夫曼树结构
	 System.out.println(ht.getHuffmanCode());//输出所有叶节点的赫夫曼编码
		
        }
}

 

4,测试结果

第0个:【叶节点值:2;父节点值:4】
第1个:【叶节点值:3;父节点值:6】
第2个:【叶节点值:2;父节点值:4】
第3个:【叶节点值:4;父节点值:8】
第4个:【叶节点值:2;父节点值:3】
第5个:【叶节点值:1;父节点值:3】
第6个:【节点值:3;父节点值:6;左孩子:1;右孩子:2】
第7个:【节点值:4;父节点值:8;左孩子:2;右孩子:2】
第8个:【节点值:6;父节点值:14;左孩子:3;右孩子:3】
第9个:【节点值:8;父节点值:14;左孩子:4;右孩子:4】
第10个:【根节点值:14;左孩子:6;右孩子:8】





我:100
 :001
b:10
c:11
是:000
a:101



 


2009.06.01日我又写道: 上面的程序对输入有严格的要求,附件中是修改后的程序,可以接受输入浮点类型。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值