java 实现最优二叉树_哈夫曼树(最优二叉树)及其Java实现
一、定义
一些定义:
节点之间的路径长度:在树中从一个结点到另一个结点所经历的分支,构成了这两个结点间的路径上的经过的分支数称为它的路径长度
树的路径长度:从树的根节点到树中每一结点的路径长度之和。在结点数目相同的二叉树中,完全二叉树的路径长度最短。
结点的权:在一些应用中,赋予树中结点的一个有某种意义的实数。
结点的带权路径长度:结点到树根之间的路径长度与该结点上权的乘积。
树的带权路径长度(Weighted Path Length of Tree:WPL):定义为树中所有叶子结点的带权路径长度之和
如下面的二叉树,叶子节点的权值分别为5、6、2、4、7,的带权路径长度计算:
最优二叉树:从已给出的目标带权结点(单独的结点) 经过一种方式的组合形成一棵树.使树的权值最小.。最优二叉树是带权路径长度最短的二叉树。根据结点的个数,权值的不同,最优二叉树的形状也各不相同。它们的共同点是:带权值的结点都是叶子结点。权值越小的结点,其到根结点的路径越长。
如,给定4个叶子结点a,b,c和d,分别带权7,5,2和4。构造如下图所示的三棵二叉树(还有许多棵),它们的带权路径长度分别为:
(a)WPL=7*2+5*2+2*2+4*2=36
(b)WPL=7*3+5*3+2*1+4*2=46
(c)WPL=7*1+5*2+2*3+4*3=35
其中(c)树的WPL最小,可以验证,它就是哈夫曼树。
注意:
① 叶子上的权值均相同时,完全二叉树一定是最优二叉树,否则完全二叉树不一定是最优二叉树。
② 最优二叉树中,权越大的叶子离根越近。
③ 最优二叉树的形态不唯一,WPL最小。
二、构造哈夫曼树
1) 根据给定的n个权值{w1, w2, w3, w4......wn}构成n棵二叉树的森林 F={T1 , T2 , T3.....Tn},其中每棵二叉树只有一个权值为wi 的根节点,其左右子树都为空;
2) 在森林F中选择两棵根节点的权值最小的二叉树,作为一棵新的二叉树的左右子树,且令新的二叉树的根节点的权值为其左右子树的权值和;
3)从F中删除被选中的那两棵子树,并且把构成的新的二叉树加到F森林中;
4)重复2 ,3 操作,直到森林只含有一棵二叉树为止,此时得到的这棵二叉树就是哈夫曼树。
构造过程如下图:
三、Java实现
对指定节点创建哈夫曼树:
package com.liuhao.DataStructures;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
public class HuffmanTree {
public static class Node {
E data;
double weight;
Node leftChild;
Node rightChild;
public Node(E data, double weight) {
super();
this.data = data;
this.weight = weight;
}
public String toString() {
return "Node[data=" + data + ", weight=" + weight + "]";
}
}
public static void main(String[] args) {
List nodes = new ArrayList();
nodes.add(new Node("A", 40.0));
nodes.add(new Node("B", 8.0));
nodes.add(new Node("C", 10.0));
nodes.add(new Node("D", 30.0));
nodes.add(new Node("E", 10.0));
nodes.add(new Node("F", 2.0));
Node root = HuffmanTree.createTree(nodes);
System.out.println(breadthFirst(root));
}
/**
* 构造哈夫曼树
*
* @param nodes
* 节点集合
* @return 构造出来的哈夫曼树的根节点
*/
private static Node createTree(List nodes) {
// 只要nodes数组中还有2个以上的节点
while (nodes.size() > 1) {
quickSort(nodes);
//获取权值最小的两个节点
Node left = nodes.get(nodes.size()-1);
Node right = nodes.get(nodes.size()-2);
//生成新节点,新节点的权值为两个子节点的权值之和
Node parent = new Node(null, left.weight + right.weight);
//让新节点作为两个权值最小节点的父节点
parent.leftChild = left;
parent.rightChild = right;
//删除权值最小的两个节点
nodes.remove(nodes.size()-1);
nodes.remove(nodes.size()-1);
//将新节点加入到集合中
nodes.add(parent);
}
return nodes.get(0);
}
/**
* 将指定集合中的i和j索引处的元素交换
*
* @param nodes
* @param i
* @param j
*/
private static void swap(List nodes, int i, int j) {
Node tmp;
tmp = nodes.get(i);
nodes.set(i, nodes.get(j));
nodes.set(j, tmp);
}
/**
* 实现快速排序算法,用于对节点进行排序
*
* @param nodes
* @param start
* @param end
*/
private static void subSort(List nodes, int start, int end) {
if (start < end) {
// 以第一个元素作为分界值
Node base = nodes.get(start);
// i从左边搜索,搜索大于分界值的元素的索引
int i = start;
// j从右边开始搜索,搜索小于分界值的元素的索引
int j = end + 1;
while (true) {
// 找到大于分界值的元素的索引,或者i已经到了end处
while (i < end && nodes.get(++i).weight >= base.weight)
;
// 找到小于分界值的元素的索引,或者j已经到了start处
while (j > start && nodes.get(--j).weight <= base.weight)
;
if (i < j) {
swap(nodes, i, j);
} else {
break;
}
}
swap(nodes, start, j);
//递归左边子序列
subSort(nodes, start, j - 1);
//递归右边子序列
subSort(nodes, j + 1, end);
}
}
public static void quickSort(List nodes){
subSort(nodes, 0, nodes.size()-1);
}
//广度优先遍历
public static List breadthFirst(Node root){
Queue queue = new ArrayDeque();
List list = new ArrayList();
if(root!=null){
//将根元素加入“队列”
queue.offer(root);
}
while(!queue.isEmpty()){
//将该队列的“队尾”元素加入到list中
list.add(queue.peek());
Node p = queue.poll();
//如果左子节点不为null,将它加入到队列
if(p.leftChild != null){
queue.offer(p.leftChild);
}
//如果右子节点不为null,将它加入到队列
if(p.rightChild != null){
queue.offer(p.rightChild);
}
}
return list;
}
}以上代码中的关键步骤包括:
(1)对list集合中所有节点进行排序;
(2)找出list集合中权值最小的两个节点;
(3)以权值最小的两个节点作为子节点创建新节点;
(4)从list集合中删除权值最小的两个节点,将新节点添加到list集合中
程序采用循环不断地执行上面的步骤,直到list集合中只剩下一个节点,最后剩下的这个节点就是哈夫曼树的根节点
四、哈夫曼编码
根据哈夫曼树可以解决报文编码的问题。假设需要把一个字符串,如“abcdabcaba”进行编码,将它转换为唯一的二进制码,但是要求转换出来的二进制码的长度最小。
假设每个字符在字符串中出现频率为W,其编码长度为L,编码字符n个,则编码后二进制码的总长度为W1L1+W2L2+…+WnLn,这恰好是哈夫曼树的处理原则。因此可以采用哈夫曼树的构造原理进行二进制编码,从而使得电文长度最短。
对于“abcdabcaba”,共有a、b、c、d4个字符,出现次数分别为4、3、2、1,相当于它们的权值,将a、b、c、d以出现次数为权值构造哈夫曼树,得到下左图的结果。
从哈夫曼树根节点开始,对左子树分配代码“0”,对右子树分配“1”,一直到达叶子节点。然后,将从树根沿着每条路径到达叶子节点的代码排列起来,便得到每个叶子节点的哈夫曼编码,如下右图。
从图中可以看出,a、b、c、d对应的编码分别为0、10、110、111,然后将字符串“abcdabcaba”转换为对应的二进制码就是0101101110101100100,长度仅为19。这也就是最短二进制编码,也称为哈夫曼编码。
java 实现最优二叉树_哈夫曼树(最优二叉树)及其Java实现相关推荐
- java 实现最优二叉树_哈夫曼树(最优二叉树) - Java实现
简介 哈夫曼树(Huffman)树又称最优二叉树,是指对于一组带有确定权值的叶子结点所构造的具有带权路径长度最短的二叉树.从树中一个结点到另一个结点之间的分支构成了两结点之间的路径,路径上的分支个数称 ...
- 最优二叉树(哈夫曼树)Java实现
此篇博客讲最优二叉树也叫哈夫曼树的原理,以及构建步骤,还有哈夫曼编码原理.建议有二叉树基础朋友学习交流.对二叉树基础可以看我的另外一篇博客二叉树的构建以及遍历 文章目录 哈夫曼树引出: 哈夫曼树原理及 ...
- JAVA实现二叉树带权路径长度和_哈夫曼树的构建与最小带权路径长度
注意:哈夫曼树并不唯一,但带权路径长度一定是相同的. 二叉树:每个结点最多含有两个子树的树称为二叉树. 定理:对于具有n个叶子结点的哈夫曼树,共有2n-1个结点. 哈夫曼树介绍 1哈夫曼树的定义 哈夫 ...
- 哈夫曼编码(基于哈夫曼树-最优二叉树,不唯一)、B树(b-树)、B+树
整合自: http://blog.csdn.net/shuangde800/article/details/7341289 http://www.cnblogs.com/Jezze/archive/2 ...
- java哈夫曼树编码_哈夫曼树的编码实验
Java哈夫曼编码实验--哈夫曼树的建立,编码与解码 建树,造树,编码,解码 一.哈夫曼树编码介绍 1.哈夫曼树: (1)定义:假设有n个权值{w1, w2, ..., wn},试构造一棵含有n个叶子 ...
- 最优二叉树(哈夫曼树)知识点
路径:在一棵树中从一个结点往下到孩子或孙子结点之间的通路 结点的路径长度:从根节点到该节点的路径上分支的数目 树的路径长度:树中每个结点的路径长度之和 结点的权:给树中的结点赋予一个某种含义的值,则该 ...
- WPL、最优二叉树(哈夫曼树)
定义:最优树,带权路径长度最短的树 基本概念: 1:路径长度:从树的一个结点到另一个结点的路径中,路径上的分支数目为路径长度 2:树的路径长度:从根结点到每个结点的路径长度之和 3:树的带权路径长度( ...
- java哈夫曼编码与译码_哈夫曼树与编码译码实现
标签: 一.哈弗曼树的基本概念. 哈夫曼树,又称最优树,是一类带权路径长度最短的树.下面有几个概念: (1)路径. 树中一个结点到另一个结点之间的分支构成这两个结点之间的路径. (2)路径长度. 路径 ...
- 深入学习二叉树(三) 霍夫曼树
深入学习二叉树(三) 霍夫曼树 1 前言 霍夫曼树是二叉树的一种特殊形式,又称为最优二叉树,其主要作用在于数据压缩和编码长度的优化. 2 重要概念 2.1 路径和路径长度 在一棵树中,从一个结点往下可 ...
最新文章
- 作业要求 20181127-1 附加作业 软件工程原则的应用实例分析
- 数学建模学习笔记(一)——层次分析模型
- 如何做好软件测试管理工作,如何才能做好软件测试工作
- 基于JAVA+SpringMVC+Mybatis+MYSQL的电费用电管理系统
- javascript--Date
- Kubernetes详解(二十六)——金丝雀发布
- oracle建立数据库的步骤,Oracle手工创建数据库的步骤
- 使用YASM编程 - 06
- 【差分约束 模板题】 洛谷P5960(未完待续)
- java软件工程师基本技能_Java软件工程师主要有什么技能
- Web Scraper爬取信息
- 案例分析 | 优衣库DTC模式之全渠道零售
- mysql生成18位纯数字id_MySQL实现注册时随机生成数字id,类似于注册qq时随机生成qq号...
- 强制使用ie浏览器使用最高版本
- 秦曾昌人工智能课程---3、机器学习中的哲学
- 连锁店客流统计计数器的应用
- oracle vault 权限,详说Oracle Vault——原理、安装与配置
- [洛谷P1902]刺杀大使
- 【云安全系列】Seccomp—云安全syscall防护利器
- STC12C5A60S2单片机IO口工作…
热门文章
- 什么是性能测试?为什么要进行性能测试?什么时候开展性能测试?性能测试流程是什么?性能测试有关术语是什么意思?
- 查询数据库历史(增删改查等)记录
- web漏洞扫描工具AWVS使用
- (二)分布式存储原理与设计
- 分布式技术原理(八):分布式存储
- linux 远程文件拷贝
- 腾图信使:将信息发送到飞书、钉钉、微信、息知
- VMware中linux添加网卡eth1后找不到网卡的问题Linux重启网卡报错:Bringing up interface eth0:1......
- 开发|MySQL新增字段踩坑
- Pillow浮雕滤镜