一、定义

一些定义:

  • 节点之间的路径长度:在从节点树中的一个节点也经历分公司,这构成的两个节点之间的路径分支的数目后这就是所谓的路径长度
  • 的路径长度:从树的根节点到树中每一结点的路径长度之和。

    在结点数目同样的二叉树中,全然二叉树的路径长度最短。

  • 结点的权:在一些应用中,赋予树中结点的一个有某种意义的实数。
  • 结点的带权路径长度:结点到树根之间的路径长度与该结点上权的乘积。
  • 树的带权路径长度(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> {
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<Node> nodes = new ArrayList<Node>(); 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<Node> 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<Node> 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<Node> 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<Node> nodes){
subSort(nodes, 0, nodes.size()-1);
} //广度优先遍历
public static List<Node> breadthFirst(Node root){
Queue<Node> queue = new ArrayDeque<Node>();
List<Node> list = new ArrayList<Node>(); 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。这是最短的二进制编码。也被称为Huffman编码。

版权声明:本文博主原创文章,博客,未经同意不得转载。

霍夫曼(最优二叉树)和Java达到的更多相关文章

  1. Java数据结构(十二)—— 霍夫曼树及霍夫曼编码

    霍夫曼树 基本介绍和创建 基本介绍 又称哈夫曼树,赫夫曼树 给定n个权值作为n个叶子节点,构造一棵二叉树,若该树的带权路径长度(wpl)达到最小,称为最优二叉树 霍夫曼树是带权路径长度最短的树,权值较 ...

  2. C# 霍夫曼二叉树压缩算法实现

    知道有的人比较懒,直接贴全部代码. 一开始一次性Code完了压缩部分代码.只调试了2,3次就成功了. 一次性写150行代码,没遇到什么bug的感觉还是蛮爽的. 写解压代码,才发现压缩代码有些细节问题. ...

  3. 赫夫曼\哈夫曼\霍夫曼编码 (Huffman Tree)

    哈夫曼树 给定n个权值作为n的叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree).哈夫曼树是带权路径长度最短的树,权值较大的结点离 ...

  4. word2vec 中的数学原理二 预备知识 霍夫曼树

    主要参考:    word2vec 中的数学原理详解                 自己动手写 word2vec 编码的话,根是不记录在编码中的 这一篇主要讲的就是霍夫曼树(最优二叉树)和编码.  ...

  5. Alink漫谈(十六) :Word2Vec源码分析 之 建立霍夫曼树

    Alink漫谈(十六) :Word2Vec源码分析 之 建立霍夫曼树 目录 Alink漫谈(十六) :Word2Vec源码分析 之 建立霍夫曼树 0x00 摘要 0x01 背景概念 1.1 词向量基础 ...

  6. 霍夫曼编码(Huffman Coding)

    霍夫曼编码(Huffman Coding)是一种编码方法,霍夫曼编码是可变字长编码(VLC)的一种. 霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符 ...

  7. CF 463A && 463B 贪心 && 463C 霍夫曼树 && 463D 树形dp && 463E 线段树

    http://codeforces.com/contest/462 A:Appleman and Easy Task 要求是否全部的字符都挨着偶数个'o' #include <cstdio> ...

  8. word2vec中关于霍夫曼树的

    再谈word2vec 标签: word2vec自然语言处理NLP深度学习语言模型 2014-05-28 17:17 16937人阅读 评论(7) 收藏 举报  分类: Felven在职场(86)    ...

  9. 基于python的二元霍夫曼编码译码详细设计

    一.设计题目 对一幅BMP格式的灰度图像(个人证件照片)进行二元霍夫曼编码和译码 二.算法设计 (1)二元霍夫曼编码: ①:图像灰度处理: 利用python的PIL自带的灰度图像转换函数,首先将彩色图 ...

  10. 采用霍夫曼编码(Huffman)画出字符串各字符编码的过程并求出各字符编码 --多媒体技术与应用

    题目:有一个字符串:cabcedeacacdeddaaaba,问题: (1)采用霍夫曼编码画出编码的过程,并写出各字符的编码 (2)根据求得的编码,求得各编码需要的总位数 (3)求出整个字符串总编码长 ...

随机推荐

  1. hdu 5092 Seam Carving

    这道题 我没看出来 他只可以往下走,我看到的 8-connected :所以今天写一下如果是 8-connected 怎么解: 其实说白了这个就是从上到下走一条线到达最后一行的距离最小: 从Map[a ...

  2. effective c++ 条款11 Handle assignment to self in operator=

    赋值给自己,听起来有些不可思议,但是却要引起重视,它很容易把自己隐藏起来. 例如 1 a[i]=a[j]; 如果 i, j的值一样? 2 *px=*py; 如果px py指向同一个object 3   ...

  3. 《SAS编程和数据挖掘商业案例》学习笔记# 19

    继续<SAS编程与数据挖掘商业案例>学习笔记,本文側重数据处理实践.包含:HASH对象.自己定义format.以及功能强大的正則表達式 一:HASH对象 Hash对象又称散列表,是依据关键 ...

  4. Canvas翻转方法

     // 普通抽奖: // ctx.drawImage(img, px, py); // 级别"翻转"帆布 ctx.translate(canvas_width, 0); ctx. ...

  5. WPF技术触屏上的应用系列(三): 视频播放器的使用及视频播放、播放、暂停、可拖动播放进度效果实现

    原文:WPF技术触屏上的应用系列(三): 视频播放器的使用及视频播放.播放.暂停.可拖动播放进度效果实现 去年某客户单位要做个大屏触屏应用,要对档案资源进行展示之用.客户端是Window7操作系统,5 ...

  6. Axis2 -POJO

    POJO,Plain Old Java Object,简单Java物. 通告Webservice 1.书写Hello.java public class Hello { public String s ...

  7. 苹果WatchKit轻松入门

    背景 前段时间苹果Apple推出 WatchKit,用于开发Apple Watch应用,同时也推出了 Xcode6.2 Beta(非稳定版,好期待稳定版)版本用于开发 Watch App.Apple ...

  8. jwt (JSON Web Token)官方说明

    http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32#appendix-A 相关文章 http://haomou.net/2014 ...

  9. 七牛对用户使用webp图片格式的使用建议

    Qiniu 七牛问题解答 Chrome浏览器是可打开WebP格式的.可是并非全部的浏览器都支持webp格式,比如360.ie等浏览器是不支持的. WebP格式,谷歌(google)开发的一种旨在加快图 ...

  10. JProgressBar的一个框架

    Frame: package swing.progress; import java.awt.BorderLayout; import java.awt.Frame; import java.awt. ...