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