上次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日我又写道: 上面的程序对输入有严格的要求,附件中是修改后的程序,可以接受输入浮点类型。