您的位置:首页 > 其它

贪婪算法-霍夫曼树 霍夫曼编码

2016-04-15 18:08 225 查看
哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的 路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。树的带权路径长度记为WPL= (W1*L1+W2*L2+W3*L3+...+Wn*Ln),N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,...n)。可以证明哈夫曼树的WPL是最小的。

哈夫曼编码步骤:

一、对给定的n个权值{W1,W2,W3,...,Wi,...,Wn}构成n棵二叉树的初始集合F= {T1,T2,T3,...,Ti,...,Tn},其中每棵二叉树Ti中只有一个权值为Wi的根结点,它的左右子树均为空。(为方便在计算机上实现算 法,一般还要求以Ti的权值Wi的升序排列。)

二、在F中选取两棵根结点权值最小的树作为新构造的二叉树的左右子树,新二叉树的根结点的权值为其左右子树的根结点的权值之和。

三、从F中删除这两棵树,并把这棵新的二叉树同样以升序排列加入到集合F中。

四、重复二和三两步,直到集合F中只有一棵二叉树为止

Java程序如下:

1.构造对象:树的节点
/**
* Huffman 树的节点对象
* @author Qing
*
*/
public class HuffmanPoint {
private int weight;//权重
private HuffmanPoint lchild, rchild;//父节点
private char value;//leaf 的char值
private String code = "";//Huffman编码

public String getCode() {
return code;
}

public void setCode(String code) {
this.code = code;
}

public HuffmanPoint(char value, int weight){
// TODO Auto-generated constructor stub
this.weight = weight;
this.value = value;
}

public void setWeight(int weight){
this.weight = weight;
}
public int getWeight(){
return this.weight;
}
public HuffmanPoint getLchild() {
return lchild;
}
public void setLchild(HuffmanPoint lchild) {
this.lchild = lchild;
}
public HuffmanPoint getRchild() {
return rchild;
}
public void setRchild(HuffmanPoint rchild) {
this.rchild = rchild;
}

public char getValue() {
return value;
}

public void setValue(char value) {
this.value = value;
}

}


1.对树的集合进行初始化。将给定的字符串进行权重计算(出现的次数),每个字符看做是一个单节点的子树。

测试字符串:

public static final char text[] = {'q','i','n','g','b','e','a','u','t','y','c','u','t','e','t','r','u','e'};


//初始化,计算每个叶子的权重,并且每个叶子作为一个单独的树
public static void init(){
int length = text.length;
int i = 0;
while(i < length){
int leaf_i = 0;
int flag = 0;
while(leaf_i < leafs.size()){
if(leafs.get(leaf_i).getValue() == text[i]){
leafs.get(leaf_i).setWeight(leafs.get(leaf_i).getWeight() + 1);//当有相同的value就将weight +1
flag = 1;
break;
}
leaf_i ++;
}
if(flag == 0){
HuffmanPoint newleaf = new HuffmanPoint(text[i],1);
leafs.add(newleaf);
}
i++;
}

trees = leafs;
for(int j = 0; j < trees.size(); j ++){
System.out.println(trees.get(j).getValue() + " " + trees.get(j).getWeight());
}
}
初始化之后的结果:



3. 构造霍夫曼树。选择森林中权重最小的两棵树合并成一棵树,将新生成的树加入森林,并且将两棵树删除,循环直至最后合并成一棵树。

//寻找森林中节点权重最小的树
public static HuffmanPoint find_min(){
int i = 1;
HuffmanPoint temp = trees.get(0);
while(i < trees.size()){
if(trees.get(i).getWeight() < temp.getWeight()){
temp = trees.get(i);
}
i ++;
}
trees.remove(temp);
return temp;

}
//构造霍夫曼树
public static void buildTree(){
HuffmanPoint lchild;
HuffmanPoint rchild;
while(trees.size() != 1){
HuffmanPoint tree_new = new HuffmanPoint('0',0);//所有不是叶子节点的value值设为0
lchild = find_min();
rchild = find_min();
System.out.println("left " + lchild.getValue() +", right "+ rchild.getValue());
tree_new.setLchild(lchild);
tree_new.setRchild(rchild);
tree_new.setWeight(lchild.getWeight() + rchild.getWeight());
//从森林中移除两个子树,添加合并后的树
trees.add(tree_new);
for(int j = 0; j < trees.size(); j ++){
System.out.print(trees.get(j).getValue() + " " + trees.get(j).getWeight() +"\t");
}
System.out.println(" ");
}

}


构造霍夫曼树的过程测试如下:



4. 对霍夫曼树进行编码并打印

//对树进行编码打印树,利用队列
public static void printTree(){
HuffmanPoint root = trees.get(0);
queue.add(root);
while(!queue.isEmpty()){
HuffmanPoint point = queue.get(0);
System.out.println(point.getValue() + " "+ point.getCode());
//将节点的左子树和右子树放入队列,并将打印出的节点从队列中取走
if(point.getLchild() != null){
HuffmanPoint lchild = point.getLchild();
HuffmanPoint rchild = point.getRchild();
lchild.setCode(point.getCode() + "0");
rchild.setCode(point.getCode() +"1");
queue.add(lchild);
queue.add(rchild);
}
queue.remove(point);
}

}


编码结果如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: