java实现哈弗曼树

编程之家收集整理的这篇文章主要介绍了java实现哈弗曼树编程之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

O(∩_∩)O~~

 

概述

 

我想学过数据结构的小伙伴一定都认识哈弗曼,这位大神发明了大名鼎鼎的“最优二叉树”,为了纪念他呢,我们称之为“哈弗曼树”。哈弗曼树可以用于哈弗曼编码,编码的话学问可就大了,比如用于压缩,用于密码学等。今天一起来看看哈弗曼树到底是什么东东。

 

概念

 

当然,套路之一,首先我们要了解一些基本概念。

 

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,构建节点。

@H_301_102@

然后将f3和b5去掉,现在是a15,c8,d6,fb8。

第三步,重复第二步,直到构建出只剩一个节点。

 

 现在是dfb14,a15,c8。

最后,

ok,这样我们的哈弗曼树就构造完成了。

 

构建的步骤

 

按照上面的逻辑,总结起来,就是一下几个步骤:

1.统计字符串中字符以及字符的出现次数

2.根据第一步的结构,创建节点;

3.对节点权值升序排序;

4.取出权值最小的两个节点,生成一个新的父节点;

5.删除权值最小的两个节点,将父节点存放到列表中;

6.重复第四五步,直到剩下一个节点;

7.将最后的一个节点赋给根节点。

 

java代码

 

原理说完了,接下来是代码实现了。

首先需要有个节点类来存放数据。

 1 package huffman;
 2 /**
 3  * 节点类
 4  * @author yuxiu
 5  *
 6  */
 7 public class Node {
 8     public String code;// 节点的哈夫曼编码
 9     int codeSize; 节点哈夫曼编码的长度
10     public String data; 节点的数据
11     int count; 节点的权值
12     public Node lChild;
13      Node rChild;
14 
15      Node() {
16     }
17 
18     public Node(String data,int count) {
19         this.data = data;
20         this.count = count;
21 22 
23     public Node( count,Node lChild,Node rChild) {
24         25         this.lChild = lChild;
26         this.rChild = rChild;
27 28 
29     30         31         32         33         34 35 }

 然后就是实现的过程了。

  1   2 
  3 import java.io.*;
  4 import java.util.*  5 
  6  Huffman {
  7     private String str; 最初用于压缩的字符串
  8     private String newStr = ""; 哈夫曼编码连接成的字符串    
  9     private Node root; 哈夫曼二叉树的根节点
 10     private boolean flag; 最新的字符是否已经存在的标签
 11     private ArrayList<String> charList; 存储不同字符的队列 相同字符存在同一位置
 12     private ArrayList<Node> NodeList; 存储节点的队列
 13    
 14      15      16      17      * 构建哈夫曼树
 18      * 
 19      * @param str
 20       21     void creatHfmTree(String str) {
 22         this.str = str;
 23         charList = new ArrayList<String>();
 24         NodeList = new ArrayList<Node> 25          1.统计字符串中字符以及字符的出现次数
 26          基本思想是将一段无序的字符串如ababccdebed放到charList里,分别为aa,bbb,cc,dd,ee
 27          并且列表中字符串的长度就是对应的权值
 28         for (int i = 0; i < str.length(); i++) {
 29             char ch = str.charAt(i);  从给定的字符串中取出字符
 30             flag = true 31             int j = 0; j < charList.size(); j++ 32                 if (charList.get(j).charAt(0) == ch) { 如果找到了同一字符
 33                     String s = charList.get(j) + ch;
 34                     charList.set(j,s);
 35                     flag = false 36                     break 37                 }
 38             }
 39             if (flag) {
 40                 charList.add(charList.size(),ch + "");
 41  42         }
 43          2.根据第一步的结构,创建节点
 44         int i = 0; i < charList.size(); i++ 45             String data = charList.get(i).charAt(0) + "";  获取charList中每段字符串的首个字符
 46             int count = charList.get(i).length();  列表中字符串的长度就是对应的权值
 47             Node node = new Node(data,count);  创建节点对象
 48             NodeList.add(i,node);  加入到节点队列
 49  50 
 51          3.对节点权值升序排序
 52         Sort(NodeList);
 53         while (NodeList.size() > 1) { 当节点数目大于一时
 54              4.取出权值最小的两个节点,生成一个新的父节点
 55              5.删除权值最小的两个节点,将父节点存放到列表中
 56             Node left = NodeList.remove(0 57             Node right = NodeList.remove(0 58             int parentWeight = left.count + right.count; 父节点权值等于子节点权值之和
 59             Node parent = new Node(parentWeight,left,right);
 60             NodeList.add(0,parent);  将父节点置于首位
 61 
 62  63          6.重复第四五步,就是那个while循环
 64          7.将最后的一个节点赋给根节点
 65         root = NodeList.get(0 66  67     68      * 升序排序
 69  70  nodelist
 71       72     void Sort(ArrayList<Node> nodelist) {
 73         int i = 0; i < nodelist.size() - 1; i++ 74             int j = i + 1; j < nodelist.size(); j++ 75                 Node temp;
 76                 if (nodelist.get(i).count > nodelist.get(j).count) {
 77                     temp = nodelist.get(i);
 78                     nodelist.set(i,nodelist.get(j));
 79                     nodelist.set(j,temp);
 80  81 
 82  83  84 
 85  86 
 87      88      * 遍历
 89  90  node
 91      *            节点
 92       93      output(Node node) {
 94         if (node.lChild != null 95             output(node.lChild);
 96  97         System.out.print(node.count + "   ");  中序遍历
 98         if (node.rChild !=  99             output(node.rChild);
100 101 102 
103      output() {
104         output(root);
105 106 107      * 主方法
108 109  args
110      111     static  main(String[] args) {
112         Huffman huff = new Huffman();创建哈弗曼对象
113         huff.creatHfmTree("sdfassvvdfgsfdfsdfs");构造树
114     }

 

总结

以上是编程之家为你收集整理的java实现哈弗曼树全部内容,希望文章能够帮你解决java实现哈弗曼树所遇到的程序开发问题。

如果觉得编程之家网站内容还不错,欢迎将编程之家网站推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您喜欢寻找一群志同道合、互帮互助的学习伙伴,可以点击下方链接加入:
编程之家官方1群
编程之家官方2群
编程之家官方3群
编程之家官方4群

相关文章

猜你在找的Java相关文章

感觉基础知识学了不少,但是一直搞不清一个项目的实际开发流程,所以就借着这个小记账本的程序梳理一下。因为楼主也是出于学习阶段的菜鸟,所以程序可能会有各种玄学的bug,希望一起提升吧。 跟着站长学到了很多
O(∩_∩)O~~ 概述 我想学过数据结构的小伙伴一定都认识哈弗曼,这位大神发明了大名鼎鼎的“最优二叉树”,为了纪念他呢,我们称之为“哈弗曼树”。哈弗曼树可以用于哈弗曼编码,编码的话学问可就大了,比如
现在编程的思想分成了两大阵营,面向过程和面向对象。现在谈谈啥是面向对象。 作为一只单身狗,谈“对象”还是很伤心很伤心的(;′⌒`)...... 先看看百度怎么说? 好吧,百度说的太抽象,我换个简单的说
1.java变量存储域 java变量的存储区域主要放在以下几个地方: (1)寄存器:可以说是最快的存储区,在C/C++中可以声明寄存器变量,但是在java中不能声明寄存器变量,只是编译器在编译时确定。
文/朱季谦 在一次Java解析xml文件的开发过程中,使用SAX解析时,出现了这样一个异常信息: Error on line 60 of document : 对实体 &quot;xxx&quot;
一.类继承Boolean的源码类定义部分如下: 1 public final class Boolean implements java.io.Serializable, 2 Comparable&l
文/朱季谦 想起刚开始接触JAVA面向对象编程时,若遇到大量流程判断语句,几乎满屏都是if-else语句,多得让自己都忘了哪里是头,哪里是尾,但是,纵然满屏是if-else,但彼时也没有觉得多别扭。等
一、案例场景 遇到过这样的场景,在定义一个static修饰的Map时,使用了大量的put()方法赋值,就类似这样—— public static final Map&lt;String,String&
微信公众号搜索 “ 程序精选 ” ,选择关注!
微信公众号搜 "程序精选"关注