1.介绍

哈夫曼树就是树的带权路径长度(即WPL)最小的树,WPL等于所有叶节点的带权路径长度之和。

而叶节点的带权路径长度=该结点的路径长度*该结点的权值。

结点的路径长度就是从根节点到该结点所经历的边数。而权值即赋给每个结点的一个数值。

(a)WPL =1*2+3*2+5*2+7*2=32

(b)WPL=1*3+3*3+5*2+7*1=29

(c)WPL=1*2+3*3+5*5+7*1=43

因此,abc中(b)图的WPL最小。

那么怎么求出WPL最小的树呢?

2.算法

假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,则哈夫曼树的构造规则为:

(1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点);

(2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;

(3)从森林中删除选取的两棵树,并将新树加入森林;

(4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。

 3.特点

(1)有n个叶节点的哈夫曼树共有2n-1个结点。

(2)权值越大的叶节点,离根节点越近,权值越小的叶节点,离根节点越远。

(3)哈夫曼树是正则二叉树,只有度为0和2的结点。

(4)哈夫曼树任意非叶节点的左右子树交换后仍是哈夫曼树。因此,哈夫曼树不唯一。

4.编码作用

等长编码:每个对象二进制长度相等。

不等长编码:每个对象二进制长度不相等。

等长编码虽然容易解码,但编码而成二进制长度太长。常用的子符编码居然也要和不常用的字符编码一样长。

对于不等长编码,对常用的字符进行相对较短的二进制编码表示,不常用的字符进行相对较长的二进制编码表示,减少了解码报文的二进制长度,但容易发生多种解码的方式。

比如说“00”可以表示‘E’,而‘0’可以表示‘G’,那么“00“即可解码成E,也可解码成GG。

因此,有了前缀码(名字很奇怪),即任何一个字符的编码都不是另一个字符的前缀的编码方式。

由于哈夫曼树编码结点向左为0,向右为1,而且只对叶节点编码,其双亲结点不编码,也就不存在一个对象的编码是另一个编码的前缀的情况。

这样,我们利用哈夫曼树,这样既能是前缀码易于解码,又能根据字符常用程度赋给其结点权值,其解码任务大大减少。

#pragma once
#include<iostream>
template<class T>
class huffman_tree
{struct huffman_node{//哈夫曼树的字符结点是哈夫曼树的叶节点T data;//编码的字符int weight;//其权值//父节点位序,根据哈夫曼算法,利用parent是否为-1可以分辨一个结点是否已经用上,用上则不为-1int parent;int left, right;//左右孩子位序huffman_node() { weight = INT_MAX; parent = left = right = -1; }};struct huffman_code{T data;//编码字符std::string code;huffman_code() = default;//code初始化为“”};huffman_node* hf_tree;//顺序结构保存哈夫曼树huffman_code* hf_code;//顺序结构保存哈夫曼码int size;int select_min();//查找最小的结点,返回位序
public:huffman_tree(int init_size,const T* d,const int* w);~huffman_tree() { delete[]hf_tree; delete[]hf_code; }void print_code();
};
template<class T>
int huffman_tree<T>::select_min()
{int w = INT_MAX;int loc = -1;for (int i = 0; i < 2*size-1; i++){if (hf_tree[i].parent == -1 && hf_tree[i].weight < w){w= hf_tree[i].weight;loc = i;}}hf_tree[loc].parent = INT_MAX;//该结点已不是在选择的范围内return loc;
}
template<class T>
huffman_tree<T>::huffman_tree(int init_size, const T* d, const int* w)
{//初始化过程size = init_size;hf_tree = new huffman_node[2 * size - 1];//结点存放处hf_code = new huffman_code[size];//编码存放处//size-1到2*size-2存放叶节点,0到size-2结点不存放字符for (int i = 0; i < size; i++){hf_tree[i + size - 1].data = d[i];hf_tree[i + size - 1].weight = w[i];hf_code[i].data = d[i];}//进行哈夫曼树的建立,我们保证0位序是根节点便于下面的编码for (int i = size-2; i >=0; i--){int p = select_min(), q = select_min();hf_tree[p].parent = hf_tree[q].parent = i;hf_tree[i].weight = hf_tree[p].weight + hf_tree[q].weight;//根据第四个性质,以下顺序可以颠倒hf_tree[i].left = p;hf_tree[i].right = q;}//进行哈夫曼树的编码for (int i = size-1; i < 2*size-1; i++){int p = hf_tree[i].parent;int s = i;while (s){if (hf_tree[p].left == s)hf_code[i - size + 1].code = '0' + hf_code[i - size + 1].code;elsehf_code[i - size + 1].code = '1' + hf_code[i - size + 1].code;s = p;p = hf_tree[s].parent;}}
}
template<class T>
void huffman_tree<T>::print_code()
{for (int i = 0; i <size; i++)std::cout << hf_code[i].data << " " << hf_code[i].code << std::endl;
}

数据结构——哈夫曼树相关推荐

  1. 数据结构---哈夫曼树

    数据结构-哈夫曼树 原理:参考趣学数据结构 代码: #include<stdio.h> #include<stdlib.h> #define N 100 #define INF ...

  2. 【数据结构——哈夫曼树及其应用】

    [数据结构--哈夫曼树及其应用] 一.哈夫曼树的基本概念 二.哈夫曼树的构造算法 (一)哈夫曼树的构造过程 (二)哈夫曼树构造算法的实现 1.初始化 2.创建树 3.完整的创建哈夫曼树代码 三.哈夫曼 ...

  3. 数据结构哈夫曼树实现26个英文字符的编码和译码

    数据结构哈夫曼树实现26英文字符的编码和译码 那么首先什么是哈夫曼树?(知道的略过,直奔下面代码就好!) 在计算机数据处理中,霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编 ...

  4. 数据结构--赫夫曼树

    数据结构 –赫夫曼树 文章目录 数据结构 一.一些概念 二.最优二叉树(赫夫曼树) 三.赫夫曼树的构造 四.赫夫曼编码 五.前缀编码 一.一些概念 路径:从树中一个结点到另一个结点之间的分支构成这两个 ...

  5. 数据结构(哈夫曼树,哈夫曼编码)入门篇,JAVA实现

    什么是哈夫曼树 哈夫曼树就是一种最优判定树,举个例子,如下一个判断逻辑 if(s<60) g=1; else if(s<70) g=2 else if(s<80) g=3 else ...

  6. 数据结构 - 赫夫曼树

    wpl最小的就是赫夫曼树(所有叶子节点的带权路径长度之和最小) 写出来两个节点连接,然后循环就可以了 package tree.huffmantree;import java.util.ArrayLi ...

  7. 数据结构--赫夫曼树及其应用

    讲解请参考 赫夫曼 ------ 赫夫曼树和赫夫曼编码的存储表示------ typedef struct {unsigned int weight;unsigned int parent,lchil ...

  8. 数据结构哈夫曼树(C语言版)

    文章目录 一. 问题 需求分析 代码分析 结构体定义使用 建立哈夫曼树,首先需要找到两个权值最小的两个叶子结点,然后建树 哈夫曼编码(我采用的是从叶子结点-->根节点,所以实际是反过来的) 使用 ...

  9. 算法与数据结构 --- 哈夫曼树及其应用

    第一部分 --- 哈夫曼树的基本概念 对一个判断树的判断次序进行改变后判断的总次数就可能截然不同 如上图,在面对一万个数据的时候,左边的判断树的判断总次数为22000次,右边的判断树的判断总次数为31 ...

最新文章

  1. I hope so 2016-Oct-10
  2. 卡内基梅隆大学机器学习系副主任邢波:AI落地现在最缺的是思维方式
  3. 树状图栏目切换_AAAI 2020 | 中山大学HCP实验室:基于树状结构策略的渐进强化学习,代码已开源...
  4. 奖学金c语言程序,奖学金 (C语言代码)
  5. centos常用网络管理命令
  6. Android loader 详解
  7. java泛型为伪泛型,什么,JAVA的泛型是伪泛型
  8. 写文献综述的28个要点
  9. git添加对勾图标 TortoiseGit安转配置
  10. hdu5294Tricks Device【最短路+网络流】
  11. 摆脱“概念化”,自动售货机玩儿“物联网”是否靠谱?
  12. 微信域名防红是怎么做出来的,原理是什么?_域名微信防封
  13. 炒股精髓:多位高手多年心血结晶(推荐)
  14. 2017全国计算机高校排名,全国计算机专业大学排名_2017计算机专业大学排名
  15. Go语言如何自定义linter(静态检查工具)
  16. php微秒,PHP 微秒
  17. TNF抑制剂相关的肿瘤风险:阿达木单抗、依那西普和英夫利昔单抗随机对照试验的荟萃分析...
  18. 摘:一张废手机卡的作用
  19. 读书笔记-人月神话15
  20. 编程是一种美德,是促使一个人不断向上发展的一种原动力

热门文章

  1. html如何设置滚动动画,滚动条触发CSS3动画
  2. php csv文件转json,php csv如何转json
  3. 微信程序开发系列教程(二)微信订阅号+人工智能问答服务
  4. [渝粤教育] 西南科技大学 英语泛读 在线考试复习资料
  5. KDD CUP 99利用决策分类树进行网络异常检测
  6. 文件锁(二)——文件锁的读锁和写锁
  7. hazelcast java_Hazelcast入门教程
  8. 计算机格式为gpt怎么更改,硬盘格式转换,手把手教你如何将硬盘mbr格式转换为gpt格式...
  9. 最大似然估计方法介绍
  10. Android 使用 Scroller 实现平滑滚动