当前位置:首页 > 开发 > 编程语言 > 编程 > 正文

哈夫曼树小结

发表于: 2011-08-12   作者:剑&箫   来源:转载   浏览:
摘要: 所谓哈夫曼树,又称为最优二叉树,要了解哈夫曼树,首先先来了解几个概念。树中一个结点到另一个结点之间的分支构成这两个结点之间的路径,路径上分支数目称为路径长度。树的长度是指从根结点到每一个叶子结点的路径长度之和。结点的带权路径长度为从从该结点到根结点之间的路径长度与结点上的权值的乘积。哈夫曼树就是带权路径长度最小的二叉树。现在我们可以根据给的任意一个整型数组构造一颗哈夫曼树,构造的思路是将数组中的每
所谓哈夫曼树,又称为最优二叉树,要了解哈夫曼树,首先先来了解几个概念。树中一个结点到另一个结点之间的分支构成这两个结点之间的路径,路径上分支数目称为路径长度。树的长度是指从根结点到每一个叶子结点的路径长度之和。结点的带权路径长度为从从该结点到根结点之间的路径长度与结点上的权值的乘积。哈夫曼树就是带权路径长度最小的二叉树。现在我们可以根据给的任意一个整型数组构造一颗哈夫曼树,构造的思路是将数组中的每一个元素构造成结点对象,然后把每一个结点当成一棵树,将所有结点当成一片森林。然后每次从所有结点中取两个最小的结点,比较小的作为左子结点,比较大的作为右子结点,它们的和作为父结点构成一颗二叉树,然后把取出的这两个结点删除,将父结点放入剩下的结点中再重复以上过程直到最后只剩下一个结点,该结点即为哈夫曼树的根结点。从以上过程看,关键在于对数组的排序以及接收新的数组,这里用到java里面提供的优先队列PriorityQueue<E>,该队列的作用是将任意无序数组元素加入到该队列中,在该队列中这些元素会按某种顺序排好,只要按顺序取出就行了。查阅API文档可知,该队列定义了六个构造器,这里用到文档中的第四个构造器实例化一个该队列的对象,由该构造器的参数定义一个类来实现该参数接口类型,代码如下所示:
/**
* 实现比较对象类型接口类,该类作为优先队列的构造方法的参数传入
* @author lenovo
*
*/
class MyComparator implements Comparator<TreeNode>{

public int compare(TreeNode o1, TreeNode o2){

return (Integer)o1.getObj() - (Integer)o2.getObj();

}

public boolean equals(Object obj){
return false;
}

}

实现了该接口之后就可以实例化一个该队列的对象,然后将数组元素添加到该队列中,最后遍历队列,每次取出最小的两个元素,按上面思路就可以构造出哈夫曼树,具体代码如下所示:

/**
* 创建最优二叉树的方法
* @param arr:传入的数组
* @param TreeNode:返回根结点
*/
public TreeNode createHuffman(int[] arr){
//实例化一个优先队列对象
PriorityQueue<TreeNode> queue = new PriorityQueue<TreeNode>(11,new MyComparator());
TreeNode root=null;
//遍历数组,将数组元素构建成结点,并添加到队列中
for (int i=0;i<arr.length;i++){
//创建结点
TreeNode node = new TreeNode(arr[i]);
//将结点添加到队列中
queue.add(node);
}

//遍历队列,每次取出两个最小元素作为叶子结点,它们的和作为父结点建立二叉树,
//并从队列中删除这两个元素,同时把它们的父结点添加到队列中
while(queue.size()!=1){
//同时取两个最小元素
TreeNode node1 = queue.poll();
TreeNode node2 = queue.poll();

//根据取得的元素创建父结点
TreeNode fnode = new TreeNode((Integer)node1.getObj()+(Integer)node2.getObj());

//建立引用关系
if ((Integer)node1.getObj()<(Integer)node2.getObj()){//如果node1小于node2,则node1作为左子结点,node2作为右子结点
fnode.setLchild(node1);
fnode.setRchild(node2);
node1.setParent(fnode);
node2.setParent(node2);
}else {//如果node1大于于node2,则node1作为右子结点,node2作为左子结点
fnode.setLchild(node2);
fnode.setRchild(node1);
node1.setParent(fnode);
node2.setParent(node2);
}

//将父结点添加到队列中
queue.add(fnode);
root = fnode;

}
return root;
}
哈夫曼树生成之后,从根结点开始,对左子树分配代码“1”,右子树分配代码“0”,一直到达叶子结点为止,然后将从树根沿每条路径到达叶子结点的代码排列起来,就可以得到哈夫曼编码了,具体代码如下所示:
/**
* 根据根结点创建哈夫曼编码
* 规则:左子结点为:1,右子结点为:0
* @param root:根结点
*/
public void createCode(TreeNode root,String code){
//首先是确定各结点的路径
//得到子结点
TreeNode Lchild = root.getLchild();

TreeNode Rchild = root.getRchild();
//打印叶子节点
if (Lchild==null&&Rchild==null){
System.out.println(root.getObj()+"的编码为:"+code);
}

if (Lchild!=null){
//递归
createCode(Lchild,code+"1");
}
if (Rchild!=null){
//递归
createCode(Rchild,code+"0");
}

}
通过以下的主函数对上面的方法进行验证,主函数为:
/**
* 程序入口
* @param args
*/
public static void main(String args[]){
//实例化一个数组
int[] a = {8,6,3,4,9};
HuffmanTree ht = new HuffmanTree();
TreeNode root = ht.createHuffman(a);
ht.printTree(root);
System.out.println();
ht.createCode(root,"");

}
运行结果为:
30 13 6 7 3 4 17 8 9
6的编码为:11
3的编码为:101
4的编码为:100
8的编码为:01
9的编码为:00

通过检验可知结果正确,这就是自己对哈夫曼树的理解,如果有不正确的地方欢迎指正。

哈夫曼树小结

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
一、哈夫曼树的概念和定义 什么是哈夫曼树? 让我们先举一个例子。 判定树: 在很多问题的处理过程
首先,先复习一下二叉树的一些基本知识 树:是一种非线性数据结构。 二叉树:是每个结点最多有两个
哈夫曼树 一.哈夫曼树的基本概念及其构造 哈夫曼树是一种最优的二叉树。既然它也是二叉树,那么肯
一、哈夫曼树的概念和定义 什么是哈夫曼树? 让我们先举一个样例。 判定树: 在非常多问题的处理过
一、哈夫曼树的定义: 哈夫曼树:又称最优二叉树,是一种带权路径最短的树。 树的路径长度:从树根
最优二叉树 1.树的路径长度   树的路径长度是从树根到树中每一结点的路径长度之和。在结点数目相
一、哈夫曼树的概念和定义 什么是哈夫曼树? 让我们先举一个样例。 判定树: 在非常多问题的处理过
哈夫曼树 压缩算法 霍夫曼编码(Huffman Coding)是一种编码方式,是一种用于无损数据压缩的熵编码
定义:给定n个带有权值的叶节点,将其组成一颗带权路径长度最小的二叉树,则该二叉树为哈夫曼树,亦
一、哈夫曼树的概念和定义 什么是哈夫曼树? 让我们先举一个例子。 判定树: 在很多问题的处理过程
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号