- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章图文详解JAVA实现哈夫曼树由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
前言 。
我想学过数据结构的小伙伴一定都认识哈夫曼,这位大神发明了大名鼎鼎的“最优二叉树”,为了纪念他呢,我们称之为“哈夫曼树”。哈夫曼树可以用于哈夫曼编码,编码的话学问可就大了,比如用于压缩,用于密码学等。今天一起来看看哈夫曼树到底是什么东东。 。
概念 。
当然,套路之一,首先我们要了解一些基本概念。 。
1、路径长度:从树中的一个结点到另一个结点之间的分支构成这两个结点的路径,路径上的分支数目称为路径长度.
2、树的路径长度:从树根到每一个结点的路径长度之和,我们所说的完全二叉树就是这种路径长度最短的二叉树.
3、树的带权路径长度:如果在树的每一个叶子结点上赋上一个权值,那么树的带权路径长度就等于根结点到所有叶子结点的路径长度与叶子结点权值乘积的总和。 。
那么我们怎么判断一棵树是否为最优二叉树呢,先看看下面几棵树:
他们的带权长度分别为:
WPL1:7*2+5*2+2*2+4*2=36 。
WPL2:7*3+5*3+2*1+4*2=46 。
WPL3:7*1+5*2+2*3+4*3=35 。
很明显,第三棵树的带权路径最短(不信的小伙伴可以试一试,要是能找到更短的,估计能拿图灵奖了),这就是我们所说的“最优二叉树(哈夫曼树)”,它的构建方法很简单,依次选取权值最小的结点放在树的底部,将最小的两个连接构成一个新结点,需要注意的是构成的新结点的权值应该等于这两个结点的权值之和,然后要把这个新结点放回我们需要构成树的结点中继续进行排序,这样构成的哈夫曼树,所有的存储有信息的结点都在叶子结点上.
概念讲完,可能有点小伙伴还是“不明觉厉”.
下面举个例子构建一下就清楚了.
有一个字符串:aaaaaaaaaabbbbbaaaaaccccccccddddddfff 。
第一步,我们先统计各个字符出现的次数,称之为该字符的权值。a 15 ,b 5, c 8, d 6, f 3.
第二步,找去这里面权值最小的两个字符,b5和f3,构建节点.
然后将f3和b5去掉,现在是a15,c8,d6,fb8.
第三步,重复第二步,直到构建出只剩一个节点.
现在是dfb14,a15,c8.
最后, 。
ok,这样我们的哈夫曼树就构造完成了。 。
构建的步骤 。
按照上面的逻辑,总结起来,就是一下几个步骤:
1.统计字符串中字符以及字符的出现次数; 。
2.根据第一步的结构,创建节点; 。
3.对节点权值升序排序; 。
4.取出权值最小的两个节点,生成一个新的父节点; 。
5.删除权值最小的两个节点,将父节点存放到列表中; 。
6.重复第四五步,直到剩下一个节点; 。
7.将最后的一个节点赋给根节点。 。
java代码 。
原理说完了,接下来是代码实现了.
首先需要有个节点类来存放数据.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
package
huffman;
/**
* 节点类
* @author yuxiu
*
*/
public
class
Node {
public
String code;
// 节点的哈夫曼编码
public
int
codeSize;
// 节点哈夫曼编码的长度
public
String data;
// 节点的数据
public
int
count;
// 节点的权值
public
Node lChild;
public
Node rChild;
public
Node() {
}
public
Node(String data,
int
count) {
this
.data = data;
this
.count = count;
}
public
Node(
int
count, Node lChild, Node rChild) {
this
.count = count;
this
.lChild = lChild;
this
.rChild = rChild;
}
public
Node(String data,
int
count, Node lChild, Node rChild) {
this
.data = data;
this
.count = count;
this
.lChild = lChild;
this
.rChild = rChild;
}
}
|
然后就是实现的过程了.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
package
huffman;
import
java.io.*;
import
java.util.*;
public
class
Huffman {
private
String str;
// 最初用于压缩的字符串
private
String newStr =
""
;
// 哈夫曼编码连接成的字符串
private
Node root;
// 哈夫曼二叉树的根节点
private
boolean
flag;
// 最新的字符是否已经存在的标签
private
ArrayList<String> charList;
// 存储不同字符的队列 相同字符存在同一位置
private
ArrayList<Node> NodeList;
// 存储节点的队列
15
16
/**
* 构建哈夫曼树
*
* @param str
*/
public
void
creatHfmTree(String str) {
this
.str = str;
charList =
new
ArrayList<String>();
NodeList =
new
ArrayList<Node>();
// 1.统计字符串中字符以及字符的出现次数
// 基本思想是将一段无序的字符串如ababccdebed放到charList里,分别为aa,bbb,cc,dd,ee
// 并且列表中字符串的长度就是对应的权值
for
(
int
i =
0
; i < str.length(); i++) {
char
ch = str.charAt(i);
// 从给定的字符串中取出字符
flag =
true
;
for
(
int
j =
0
; j < charList.size(); j++) {
if
(charList.get(j).charAt(
0
) == ch) {
// 如果找到了同一字符
String s = charList.get(j) + ch;
charList.set(j, s);
flag =
false
;
break
;
}
}
if
(flag) {
charList.add(charList.size(), ch +
""
);
}
}
// 2.根据第一步的结构,创建节点
for
(
int
i =
0
; i < charList.size(); i++) {
String data = charList.get(i).charAt(
0
) +
""
;
// 获取charList中每段字符串的首个字符
int
count = charList.get(i).length();
// 列表中字符串的长度就是对应的权值
Node node =
new
Node(data, count);
// 创建节点对象
NodeList.add(i, node);
// 加入到节点队列
}
// 3.对节点权值升序排序
Sort(NodeList);
while
(NodeList.size() >
1
) {
// 当节点数目大于一时
// 4.取出权值最小的两个节点,生成一个新的父节点
// 5.删除权值最小的两个节点,将父节点存放到列表中
Node left = NodeList.remove(
0
);
Node right = NodeList.remove(
0
);
int
parentWeight = left.count + right.count;
// 父节点权值等于子节点权值之和
Node parent =
new
Node(parentWeight, left, right);
NodeList.add(
0
, parent);
// 将父节点置于首位
}
// 6.重复第四五步,就是那个while循环
// 7.将最后的一个节点赋给根节点
root = NodeList.get(
0
);
}
/**
* 升序排序
*
* @param nodelist
*/
public
void
Sort(ArrayList<Node> nodelist) {
for
(
int
i =
0
; i < nodelist.size() -
1
; i++) {
for
(
int
j = i +
1
; j < nodelist.size(); j++) {
Node temp;
if
(nodelist.get(i).count > nodelist.get(j).count) {
temp = nodelist.get(i);
nodelist.set(i, nodelist.get(j));
nodelist.set(j, temp);
}
}
}
}
/**
* 遍历
*
* @param node
* 节点
*/
public
void
output(Node node) {
if
(node.lChild !=
null
) {
output(node.lChild);
}
System.out.print(node.count +
" "
);
// 中序遍历
if
(node.rChild !=
null
) {
output(node.rChild);
}
}
public
void
output() {
output(root);
}
/**
* 主方法
*
* @param args
*/
public
static
void
main(String[] args) {
Huffman huff =
new
Huffman();
//创建哈弗曼对象
huff.creatHfmTree(
"sdfassvvdfgsfdfsdfs"
);
//构造树
}
|
总结 。
以上就是基于JAVA实现哈夫曼树的全部内容,希望这篇文章对大家学习使用JAVA能有所帮助。如果有疑问可以留言讨论.
最后此篇关于图文详解JAVA实现哈夫曼树的文章就讲到这里了,如果你想了解更多关于图文详解JAVA实现哈夫曼树的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
关于 B 树与 B+ 树,网上有一个比较经典的问题:为什么 MongoDb 使用 B 树,而 MySQL 索引使用 B+ 树? 但实际上 MongoDb 真的用的是 B 树吗?
如何将 R* Tree 实现为持久(基于磁盘)树?保存 R* 树索引或保存叶值的文件的体系结构是什么? 注意:此外,如何在这种持久性 R* 树中执行插入、更新和删除操作? 注意事项二:我已经实现了一个
目前,我正在努力用 Java 表示我用 SML 编写的 AST 树,这样我就可以随时用 Java 遍历它。 我想知道是否应该在 Java 中创建一个 Node 类,其中包含我想要表示的数据,以及一个数
我之前用过这个库http://www.cs.umd.edu/~mount/ANN/ .但是,它们不提供范围查询实现。我猜是否有一个 C++ 范围查询实现(圆形或矩形),用于查询二维数据。 谢谢。 最佳
在进一步分析为什么MySQL数据库索引选择使用B+树之前,我相信很多小伙伴对数据结构中的树还是有些许模糊的,因此我们由浅入深一步步探讨树的演进过程,在一步步引出B树以及为什么MySQL数据库索引选择
书接上回,今天和大家一起动手来自己实现树。 相信通过前面的章节学习,大家已经明白树是什么了,今天我们主要针对二叉树,分别使用顺序存储和链式存储来实现树。 01、数组实现 我们在上一节中说过,
书节上回,我们接着聊二叉树,N叉树,以及树的存储。 01、满二叉树 如果一个二叉树,除最后一层节点外,每一层的节点数都达到最大值,即每个节点都有两个子节点,同时所有叶子节点都在最后一层,则这个
树是一种非线性数据结构,是以分支关系定义的层次结构,因此形态上和自然界中的倒挂的树很像,而数据结构中树根向上树叶向下。 什么是树? 01、定义 树是由n(n>=0)个元素节点组成的
操作系统的那棵“树” 今天从一颗 开始,我们看看如何从小树苗长成一颗苍天大树。 运转CPU CPU运转起来很简单,就是不断的从内存取值执行。 CPU没有好好运转 IO是个耗费时间的活,如果CPU在取值
我想为海洋生物学类(class)制作一个简单的系统发育树作为教育示例。我有一个具有分类等级的物种列表: Group <- c("Benthos","Benthos","Benthos","Be
我从这段代码中删除节点时遇到问题,如果我插入数字 12 并尝试删除它,它不会删除它,我尝试调试,似乎当它尝试删除时,它出错了树的。但是,如果我尝试删除它已经插入主节点的节点,它将删除它,或者我插入数字
B+ 树的叶节点链接在一起。将 B+ 树的指针结构视为有向图,它不是循环的。但是忽略指针的方向并将其视为链接在一起的无向叶节点会在图中创建循环。 在 Haskell 中,如何将叶子构造为父内部节点的子
我在 GWT 中使用树控件。我有一个自定义小部件,我将其添加为 TreeItem: Tree testTree = new Tree(); testTree.addItem(myWidget); 我想
它有点像混合树/链表结构。这是我定义结构的方式 struct node { nodeP sibling; nodeP child; nodeP parent; char
我编写了使用队列遍历树的代码,但是下面的出队函数生成错误,head = p->next 是否有问题?我不明白为什么这部分是错误的。 void Levelorder(void) { node *tmp,
例如,我想解析以下数组: var array1 = ["a.b.c.d", "a.e.f.g", "a.h", "a.i.j", "a.b.k"] 进入: var json1 = { "nod
问题 -> 给定一棵二叉树和一个和,确定该树是否具有从根到叶的路径,使得沿路径的所有值相加等于给定的和。 我的解决方案 -> public class Solution { public bo
我有一个创建 java 树的任务,它包含三列:运动名称、运动类别中的运动计数和上次更新。类似的东西显示在下面的图像上: 如您所见,有 4 种运动:水上运动、球类运动、跳伞运动和舞蹈运动。当我展开 sk
我想在 H2 数据库中实现 B+ Tree,但我想知道,B+ Tree 功能在 H2 数据库中可用吗? 最佳答案 H2 已经使用了 B+ 树(PageBtree 类)。 关于mysql - H2数据库
假设我们有 5 个字符串数组: String[] array1 = {"hello", "i", "cat"}; String[] array2 = {"hello", "i", "am"}; Str
我是一名优秀的程序员,十分优秀!