相关介绍:

 树形结构除了应用于查找和排序等操作时能调高效率,它在信息通讯领域也有着广泛的应用。哈弗曼(Huffman)树就是一种在编码技术方面得到广泛应用的二叉树,它同时也是一种最优二叉树。

哈弗曼树相关的的基本概念:

 为了给出哈弗曼树的定义,从以下几个基本概念出发并进行描述。

  1. 节点间的路径和节点的路径长度:所谓节点间的路径是指一个节点到另一个节点所经历的节点和分支序列。节点的路径长度是指从根节点到该节点间的路径上的分支数目。

  2. 节点的权和节点的带权路径:在实际应用中,人们往往会给树中的每一个节点赋予一个具有某种实际意义的数值,这个数值称为节点的权值。节点的带权路径长度就是该节点的路径长度与该节点的权值的乘积。

  3. 树的带权路径长度:树的带权路径长度就是树中所有叶节点的带权路径长度之和,通常记为:\(WPL=\sum_{i=1}^{n}W_{i} \times L_{i}\)其中,n为叶节点的个数,\(W_{i}\)为第i个叶节点的权值,\(L_{i}\)为第i个叶节点的路径长度

  4. 最优二叉树:给定n个权值并作为n个叶节点按一定规则构造一棵二叉树,使得其带权路径长度达到最小值,则这棵二叉树被称为最优二叉树。下图展示了具有不同带权路径长度的二叉树,其中,第二棵树为最优二叉树

哈弗曼树和哈弗曼编码的构造方法

 哈弗曼树的构造步骤如下所示:

 假设n个叶节点的权值分别为{w1,w2,...,wn},则

  1. 由已知给定的n个权值{w1,w2,w3,...,wn},构造一个由n棵二叉树所构成的森林F={T1,,T2,T3,...,Tn},其中每一棵二叉树只有一个根节点,并且根节点的权值分别为w1,w2,....,wn

  2. 在二叉树森林F中选取根节点的权值最小和次小的两棵二叉树,分别把它们作为左子树和右子树去构造一棵新二叉树,新二叉树的根节点权值为其左、右子树根节点的权值之和

  3. 作为新二叉树的左右子树的两棵二叉树从森林F中删除。将新产生的二叉树加入到森林F中

  4. 重复步骤2和步骤3,直到森林中只剩下一棵二叉树为止,则这棵二叉树就是所构成的哈弗曼树

下图展示了哈弗曼树的构造过程:

哈弗曼树构造过程的代码实现

 以下其代码演示了哈弗曼树的构造实现其中,测试代码所用的图如下所示:

相关代码:

package all_in_tree;

import java.util.Comparator;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue; /**
* 该类用于演示哈弗曼树的构造过程
* @author 学徒
*
*/
public class Huffman
{
//哈弗曼树的根节点
private HuffmanNode root;
//一个优先级队列,确保每次取出的均为节点中其权值最小的节点
private Queue<HuffmanNode> q;
/**
* 用于初始化,其优先队列
*/
public Huffman()
{
Comparator<HuffmanNode> cmp=new Comparator<HuffmanNode>()
{
@Override
public int compare(HuffmanNode obj1,HuffmanNode obj2)
{
int obj1Number=obj1.weight;
int obj2Number=obj2.weight;
if(obj1Number>obj2Number)
return 1;
else if(obj1Number<obj2Number)
return -1;
else
return 0;
}
};
q=new PriorityQueue<HuffmanNode>(11,cmp);
}
/**
* 用于添加节点到优先队列中,进行哈弗曼树的构造
* @param node
*/
public void addHuffmanNode(HuffmanNode node)
{
q.add(node);
}
/**
* 用于构造哈弗曼树
*/
public HuffmanNode createHuffmanTree()
{
while(!q.isEmpty()&&q.size()>=2)
{
HuffmanNode node1=q.poll();
HuffmanNode node2=q.poll();
HuffmanNode newNode=new HuffmanNode();
newNode.weight=node1.weight+node2.weight;
newNode.left=node1;
newNode.right=node2;
q.add(newNode);
}
if(!q.isEmpty())
this.root=q.poll();
return this.root;
}
/**
* 用于测试相关的代码
*/
public static void main(String[] args)
{
Huffman tree=new Huffman();
for(int i=0;i<5;i++)
{
tree.addHuffmanNode(new HuffmanNode((char)('A'+i),i+1));
}
HuffmanNode root=tree.createHuffmanTree();
System.out.println("其最高顶点的权值"+root.weight);
//对该哈弗曼树进行层次遍历
Queue<HuffmanNode> q=new LinkedList<HuffmanNode>();
q.add(root);
while(!q.isEmpty())
{
HuffmanNode node=q.poll();
System.out.print(node.weight+"\t");
if(node.left!=null)
q.add(node.left);
if(node.right!=null)
q.add(node.right);
}
}
}
/**
* 用于创建哈弗曼树的节点类的描述
* @author 学徒
*
*/
class HuffmanNode
{
//用于存放相关的数据
Object data;
//用于记录该节点的权
int weight;
//该节点的左孩子
HuffmanNode left;
//该节点的右孩子
HuffmanNode right;
public HuffmanNode()
{
}
public HuffmanNode(Object data,int weight)
{
this.data=data;
this.weight=weight;
}
} 运行结果: 其最高顶点的权值15
15 6 9 3 3 4 5 1 2

回到目录|·(工)·)

K:哈弗曼树的更多相关文章

  1. HDU2527:Safe Or Unsafe(哈弗曼树)

    Problem Description Javac++ 一天在看计算机的书籍的时候,看到了一个有趣的东西!每一串字符都可以被编码成一些数字来储存信息,但是不同的编码方式得到的储存空间是不一样的!并且当 ...

  2. SLT 优先队列 哈弗曼树最小带权路径

    与普通的队列不同,普通的队列是先进先出的,而优先队列出队的顺序不是先进先出,而是大(或者小)元素先出队,需要#include <queue> 成员函数 成员函数 作用 empty() 判断 ...

  3. java实现哈弗曼树

    O(∩_∩)O~~ 概述 我想学过数据结构的小伙伴一定都认识哈弗曼,这位大神发明了大名鼎鼎的“最优二叉树”,为了纪念他呢,我们称之为“哈弗曼树”.哈弗曼树可以用于哈弗曼编码,编码的话学问可就大了,比如 ...

  4. 哈弗曼树的理解和实现(Java)

    哈弗曼树概述 哈弗曼树又称最优树,是一种带权路径长度最短的树,在实际中有广泛的用途.哈弗曼树的定义,涉及路径.路径长度.权等概念.哈弗曼树可以用于哈弗曼编码,用于压缩,用于密码学等. 哈弗曼树的一些定 ...

  5. PKU 1521 Entropy(简单哈弗曼树_水过)

    题目大意:原题链接 给你一个字符串,首先是计算出一个按正常编码的编码长度,其次是计算出一个用霍夫曼编码的编码长度,最后求正常编码的长度除以霍夫曼编码长度的比值,保留一位小数. 解题思路:需要知道 1. ...

  6. POJ 3253 Fence Repair(简单哈弗曼树_水过)

    题目大意:原题链接 锯木板,锯木板的长度就是花费.比如你要锯成长度为8 5 8的木板,最简单的方式是把21的木板割成13,8,花费21,再把13割成5,8,花费13,共计34,当然也可以先割成16,5 ...

  7. Python 数据结构与算法 —— 哈弗曼树

    1. 从扩充二叉树到哈弗曼树 扩充二叉树:对二叉树 T,加入足够多的新叶节点(而不是任意),使 T 的原有结点都变成度数为 2 的分支节点,得到的二叉树称为 T 的扩充二叉树. 对于扩充二叉树而言, ...

  8. java实现哈弗曼树和哈夫曼树压缩

    本篇博文将介绍什么是哈夫曼树,并且如何在java语言中构建一棵哈夫曼树,怎么利用哈夫曼树实现对文件的压缩和解压.首先,先来了解下什么哈夫曼树. 一.哈夫曼树 哈夫曼树属于二叉树,即树的结点最多拥有2个 ...

  9. POJ 3253 Fence Repair【哈弗曼树/贪心/优先队列】

    Fence Repair Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 53645   Accepted: 17670 De ...

随机推荐

  1. 大数据学习(7)Hadoop高可用

    HDFS高可用 通过主从切换实现单NameNode高可用.通过Federation:水平扩展来联合多NameNode个: NameNode高可用 把edits日志从原来的nameNode中分离出来,存 ...

  2. 什么是 stack?- 每天5分钟玩转 Docker 容器技术(111)

    什么是 stack ?在回答这个问题之前我们先回忆一下前面部署 WordPress 应用的过程: 首先创建 secret. 然后创建 MySQL service,这是 WordPress 依赖的服务. ...

  3. idea svn 的使用----转载,挺好的

    Intellij IDEA svn的使用记录 这里的忽略一直灰色的,可以进入 这里的版本控制里进行忽略选择 或者 这里进行添加 这里有三个选择 按照顺序 1.忽略指定的文件 2.忽略文件夹下所有文件 ...

  4. springboot学习笔记-4 整合Druid数据源和使用@Cache简化redis配置

    一.整合Druid数据源 Druid是一个关系型数据库连接池,是阿里巴巴的一个开源项目,Druid在监控,可扩展性,稳定性和性能方面具有比较明显的优势.通过Druid提供的监控功能,可以实时观察数据库 ...

  5. Git使用简单总结

    创建版本库git add加入到暂存区git commit -m" "加入到分支 时光机穿梭git satus查看仓库的当前状态git diff file 查看修改内容 版本回退HE ...

  6. Android开发——Toast知识

    Toast.makeText(this, "内容", Toast.LENGTH_SHORT).show(); 直接显示一个Toast,第三个参数是时间的长短,还有一个Toast.L ...

  7. Noip2016换教室(期望+DP)

    Description 题目链接:Luogu Solution 这题结合了DP和概率与期望,其实只要稍微知道什么是期望就可以了, 状态的构造很关键,\(F[i][j][0/1]\)表示已经到第\(i\ ...

  8. HTML的三种布局:DIV+CSS、FLEX、GRID

    Div+css布局 也就是盒子模型,有W3C盒子模型,IE盒子模型.盒子模型由四部分组成margin.border.padding.content. 怎么区别这两种模型呢,区别在于w3c中的width ...

  9. softmax分类算法原理(用python实现)

    逻辑回归神经网络实现手写数字识别 如果更习惯看Jupyter的形式,请戳Gitthub_逻辑回归softmax神经网络实现手写数字识别.ipynb 1 - 导入模块 import numpy as n ...

  10. bzoj 3675: [Apio2014]序列分割

    Description 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列.为了得到k+1个子序列,小H需要重复k次以下的步骤: 1.小H首 ...