`
剑&箫
  • 浏览: 53058 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

哈夫曼树小结

    博客分类:
  • Java
阅读更多
所谓哈夫曼树,又称为最优二叉树,要了解哈夫曼树,首先先来了解几个概念。树中一个结点到另一个结点之间的分支构成这两个结点之间的路径,路径上分支数目称为路径长度。树的长度是指从根结点到每一个叶子结点的路径长度之和。结点的带权路径长度为从从该结点到根结点之间的路径长度与结点上的权值的乘积。哈夫曼树就是带权路径长度最小的二叉树。现在我们可以根据给的任意一个整型数组构造一颗哈夫曼树,构造的思路是将数组中的每一个元素构造成结点对象,然后把每一个结点当成一棵树,将所有结点当成一片森林。然后每次从所有结点中取两个最小的结点,比较小的作为左子结点,比较大的作为右子结点,它们的和作为父结点构成一颗二叉树,然后把取出的这两个结点删除,将父结点放入剩下的结点中再重复以上过程直到最后只剩下一个结点,该结点即为哈夫曼树的根结点。从以上过程看,关键在于对数组的排序以及接收新的数组,这里用到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

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

相关推荐

    C语言编码哈夫曼树

    //m为结点数,一棵有n个叶子结点的哈夫曼树共有2n-1个结点,可以存储在一个大小为2n-1的一维数组中 HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//0号单元未用 //--------初始化哈弗曼树------- for(p=HT+1,i=...

    课程设计哈夫曼树的应用

    一、课程设计题目:哈夫曼树应用 二、课程设计要求: 1) 从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树并将它存于文件hfmTree中.将已在内存中的哈夫曼树以...6.小结 14 参考文献 15 附录:源程序代码 16

    哈夫曼树 c数据结构

    将已在内存中的哈夫曼树以直观的方式(树或凹凸表形式)显示在屏幕上,同时将此字符形式的哈夫曼树写入文件treeprint中。 实现提示: 1、用户界面可以设计为“菜单”方式:显示上述功能号,再加上“E”表示结束运...

    构造哈夫曼树之后,求每一个字符的编码需要走一条从叶子结点到根结点的路径

    在哈夫曼树中,没有度为1的结点,结点总数是n0+n2(其中n0表示二叉树中度为0的结点数,n2表示度为2的结点数),而由二叉树的性质知道n0=n2+1,所以一棵哈夫曼树中结点总数是2n0-1。 由此可以得出:任何n个字符的...

    哈夫曼压缩

    利用哈夫曼编码进行信息通讯可以大大提高信道利用率,缩短信息传输时间,降低传输成本。...将已在内存中的哈夫曼树以直观的方式 (树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件treeprint中。

    哈夫曼编码动态绘制小软件,是大二做的一份结课作业

    小程序提供了两种功能的哈夫曼编码方式: 一、读取本地文件的字符: 对其进行哈夫曼编码后输出编码后的文件到指定文本文件。 二、用户输入待分析字符: ... 哈夫曼树的构建过程动态显示等功能。

    第六章 树和二叉树作业及答案(100分).docx

    构造一棵哈夫曼树(6分),给出每个字符的哈夫曼编码(4分),并计算哈夫曼树的加权路径长度WPL(2分)。 (符合WPL最小的均为哈夫曼树,答案不唯一) 哈夫曼编码: 2. 假设用于通信的电文由字符集{a,b,c,d,e,f,g}中...

    CCF中学生计算机程序设计提高篇(完整版)

    2.5 哈夫曼树及其应用 2.6 二叉堆及其应用 2.7 二叉排序树及其应用.. 本章小结 第3章集合与并查集 3.1 集合与并查集...... 3.2 并查集的基本操作 3.3并查集的应用 本章小结 第4章图及其应用 4.1 图的基本概念 4.2 图...

    Delphi算法与数据结构 源码(上)

    1.4小结 第2章数组 2.1数组 2.2Delphi中的数组类型 2.3TList类和指针数组 2.4磁盘数组 2.5小结 第3章链表、栈和队列 3.1单链表 3.2双向链表 3.3链表的优缺点 3.4栈 3.5队列 3.6小结 .第4章查找 4.1比较...

    数据结构试题A(04)1

    1. 数据结构中, ( )是线性结构 2. 树型结构中元素间存在( )的关系 3. ( )是下面的有向图的拓扑有序序列 4. 在有 n 个叶子结点的哈夫曼树中结

    Delphi算法与数据结构 源码(下)

    1.4小结 第2章数组 2.1数组 2.2Delphi中的数组类型 2.3TList类和指针数组 2.4磁盘数组 2.5小结 第3章链表、栈和队列 3.1单链表 3.2双向链表 3.3链表的优缺点 3.4栈 3.5队列 3.6小结 .第4章查找 4.1比较...

    突破程序员基本功的16课.part2

    1.3 小结 第2课 对象与内存控制 2.1 实例变量和类变量 2.1.1 实例变量和类变量的属性 2.1.2 实例变量的初始化时机 2.1.3 类变量的初始化时机 2.2 父类构造器 2.2.1 隐式调用和显式调用 2.2.2 访问子类对象...

    java数据结构与算法第二版

    小结 问题 第2章 数组 Array专题Applet Java中数组的基础知识 将程序划分成类 类接口 Ordered专题applet 有序数组的Java代码 对数 存储对象 大O表示法 为什么不用数组表示一切? 小结 问题 实验 编程...

    Java数据结构和算法(第二版)

    小结 问题 第2章 数组 Array专题Applet Java中数组的基础知识 将程序划分成类 类接口 Ordered专题applet 有序数组的Java代码 对数 存储对象 大O表示法 为什么不用数组表示一切? 小结 问题 实验 编程作业 第3章 ...

    数据结构与算法分析_Java_语言描述

    3.3.2 栈的实现 3.3.3 应用 3.4 队列ADT 3.4.1 队列模型 3.4.2 队列的数组实现 3.4.3 队列的应用 小结 练习 第4章 树 4.1 预备知识 4.1.1 树的实现 4.1.2 树的遍历及应用 4.2 二叉树 4.2.1 实现 ...

    Java数据结构和算法中文第二版

    小结 问题 第2章 数组 Array专题Applet Java中数组的基础知识 将程序划分成类 类接口 Ordered专题applet 有序数组的Java代码 对数 存储对象 大O表示法 为什么不用数组表示一切? 小结 问题 实验 编程...

    哈弗曼编码 - 数据结构课程 设计报告

    摘要 2 目录 3 一.设计目的 3 二.需求分析 5 2.1哈夫曼编码/译码器简介 5 2.2需求分析 5 三....3.1问题分析哈夫曼树的定义 5 四.详细设计 7 4.1 源代码 7 4.2运行结果 22 五.调试分析 23 六.小结 25

    Java数据结构和算法中文第二版(2)

    小结 问题 第2章 数组 Array专题Applet Java中数组的基础知识 将程序划分成类 类接口 Ordered专题applet 有序数组的Java代码 对数 存储对象 大O表示法 为什么不用数组表示一切? 小结 问题 实验 ...

    算法设计与分析王晓东

    小结 习题 第2章 递归与分治策略 2.1 速归的概念 2.2 分治法的基本思想 2.3 二分搜索技术 2.4 大整数的乘法 2.5 Strassen矩阵乘法 2.6 棋盘覆盖 2.7 合并排序 2.8 快速排序 2.9 线性时间选择 2.10 最接近点对问题 ...

Global site tag (gtag.js) - Google Analytics