Huffman树(哈夫曼树)

article/2025/9/29 1:49:23

哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。树的带权路径长度记为WPL=(W1*L1+W2*L2+W3*L3+...+Wn*Ln),N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,...n)。可以证明哈夫曼树的WPL是最小的。

什么是哈夫曼树呢?

样例解释

哈夫曼树是一种带权路径长度最短的二叉树,也称为最优二叉树。下面用一幅图来说明。

它们的带权路径长度分别为:

图a: WPL=5*2+7*2+2*2+13*2=54

图b: WPL=5*3+2*3+7*2+13*1=48

 设 根节点深度为 0

WPL

理解就是各个点的编码值和在哈夫曼生成树上的深度的乘积的和

可见,图b的带权路径长度较小,我们可以证明图b就是哈夫曼树(也称为最优二叉树)。

 

构建哈夫曼树 —————— 选集合中最小的两个(every)

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

  1. 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点);
  2. 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;
  3. 从森林中删除选取的两棵树,并将新树加入森林;
  4. 重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。

三,哈夫曼编码

利用哈夫曼树求得的用于通信的二进制编码称为哈夫曼编码。树中从根到每个叶子节点都有一条路径,对路径上的各分支约定指向左子树的分支表示”0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为各个叶子节点对应的字符编码,即是哈夫曼编码。

就拿上图例子来说:

A,B,C,D对应的哈夫曼编码分别为:111,10,110,0

用图说明如下:

记住,设计电文总长最短的二进制前缀编码,就是以n个字符出现的频率作为权构造一棵哈夫曼树,由哈夫曼树求得的编码就是哈夫曼编码

对N(≥)个权值均不相同的字符构造哈夫曼树,则树中任一非叶结点的权值一定不小于下一层任一结点的权值。

正确:

哈夫曼树的构造特点,为了使得WPL值最小,那么越是值大的节点,他在哈夫曼生成树上的深度越小

可以根据上述公式证明

,假设WPL值是个定值,增加val(i),要保持WPL的值不改变,那么deep(i)必须相应的减少。

 

对N(N≥2)个权值均不相同的字符构造哈夫曼树。下列关于该哈夫曼树的叙述中,错误的是: 

1. 先去理解哈夫曼树的构造过程,优先队列,每次取两个val最小的点,进行组合,所以,Huffman树中不会存在度数为0的点

2.同理,下面会给出代码;

3.1-1已经证明

4.错误

n 个数值,进行编码,求解WPL值的代码,stl 优先队列实现

代码很重要,最好记下来

#include<bits/stdc++.h>
#define LL long long  
#define exp 1e-9  
#define MAXN 1000010          
using namespace std;  int main( )    
{    
//  freopen("D:\\in.txt","r",stdin);  int n,i;  LL sum,tmp,q1,q2;  scanf("%d",&n);  
//构建小顶堆priority_queue<LL,vector<LL>,greater<LL> > pq;  for(i=1;i<=n;i++)  {  scanf("%lld",&tmp);  pq.push(tmp);  }  sum=0;  if(n==1)  {  printf("%lld\n",tmp);  }  else  {  while(!pq.empty())  {  q1=pq.top();  pq.pop();  if(pq.empty())  {  printf("%lld\n",sum);  break;  }  else  {  q2=pq.top();  pq.pop();  tmp=q1+q2;  pq.push(tmp);  sum+=tmp;  }  }  }  return 0;    
}    

2-5

已知字符集{ a, b, c, d, e, f, g, h }。若各字符的哈夫曼编码依次是 0100, 10, 0000, 0101, 001, 011, 11, 0001,则编码序列 0100011001001011110101 的译码结果是:

这种题目:枚举暴力尝试:

 C语言实现Huffman , 便于理解编码过程,做题推荐上面的代码,不推荐记忆;

#include <stdio.h>
#include<stdlib.h>
#include<string>
#include <iostream>#define MAXBIT      100
#define MAXVALUE  10000
#define MAXLEAF     30
#define MAXNODE    MAXLEAF*2 -1typedef struct 
{int bit[MAXBIT];int start;
} HCodeType;        /* 编码结构体 */
typedef struct
{int weight;int parent;int lchild;int rchild;char value;
} HNodeType;        /* 结点结构体 *//* 构造一颗哈夫曼树 */
void HuffmanTree (HNodeType HuffNode[MAXNODE],  int n)
{ /* i、j: 循环变量,m1、m2:构造哈夫曼树不同过程中两个最小权值结点的权值,x1、x2:构造哈夫曼树不同过程中两个最小权值结点在数组中的序号。*/int i, j, m1, m2, x1, x2;/* 初始化存放哈夫曼树数组 HuffNode[] 中的结点 */for (i=0; i<2*n-1; i++){HuffNode[i].weight = 0;//权值 HuffNode[i].parent =-1;HuffNode[i].lchild =-1;HuffNode[i].rchild =-1;HuffNode[i].value=' '; //实际值,可根据情况替换为字母  } /* end for *//* 输入 n 个叶子结点的权值 */for (i=0; i<n; i++){printf ("Please input char of leaf node: ", i);scanf ("%c",&HuffNode[i].value);getchar();} /* end for */for (i=0; i<n; i++){printf ("Please input  weight of leaf node: ", i);scanf ("%d",&HuffNode[i].weight);getchar();} /* end for *//* 循环构造 Huffman 树 */for (i=0; i<n-1; i++){m1=m2=MAXVALUE;     /* m1、m2中存放两个无父结点且结点权值最小的两个结点 */x1=x2=0;/* 找出所有结点中权值最小、无父结点的两个结点,并合并之为一颗二叉树 */for (j=0; j<n+i; j++){if (HuffNode[j].weight < m1 && HuffNode[j].parent==-1){m2=m1; x2=x1; m1=HuffNode[j].weight;x1=j;}else if (HuffNode[j].weight < m2 && HuffNode[j].parent==-1){m2=HuffNode[j].weight;x2=j;}} /* end for *//* 设置找到的两个子结点 x1、x2 的父结点信息 */HuffNode[x1].parent  = n+i;HuffNode[x2].parent  = n+i;HuffNode[n+i].weight = HuffNode[x1].weight + HuffNode[x2].weight;HuffNode[n+i].lchild = x1;HuffNode[n+i].rchild = x2;printf ("x1.weight and x2.weight in round %d: %d, %d\n", i+1, HuffNode[x1].weight, HuffNode[x2].weight);  /* 用于测试 */printf ("\n");} /* end for */} /* end HuffmanTree *///解码 
void decodeing(char string[],HNodeType Buf[],int Num)
{int i,tmp=0,code[1024];int m=2*Num-1;char *nump;char num[1024];for(i=0;i<strlen(string);i++){if(string[i]=='0')num[i]=0;        elsenum[i]=1;                    } i=0;nump=&num[0];while(nump<(&num[strlen(string)])){tmp=m-1;while((Buf[tmp].lchild!=-1)&&(Buf[tmp].rchild!=-1)){if(*nump==0){tmp=Buf[tmp].lchild ;          } else tmp=Buf[tmp].rchild;nump++;} printf("%c",Buf[tmp].value);                                  }
}int main(void)
{HNodeType HuffNode[MAXNODE];            /* 定义一个结点结构体数组 */HCodeType HuffCode[MAXLEAF],  cd;       /* 定义一个编码结构体数组, 同时定义一个临时变量来存放求解编码时的信息 */int i, j, c, p, n;char pp[100];printf ("Please input n:\n");scanf ("%d", &n);HuffmanTree (HuffNode, n);for (i=0; i < n; i++){cd.start = n-1;c = i;p = HuffNode[c].parent;while (p != -1)   /* 父结点存在 */{if (HuffNode[p].lchild == c)cd.bit[cd.start] = 0;elsecd.bit[cd.start] = 1;cd.start--;        /* 求编码的低一位 */c=p;                    p=HuffNode[c].parent;    /* 设置下一循环条件 */} /* end while *//* 保存求出的每个叶结点的哈夫曼编码和编码的起始位 */for (j=cd.start+1; j<n; j++){ HuffCode[i].bit[j] = cd.bit[j];}HuffCode[i].start = cd.start;} /* end for *//* 输出已保存好的所有存在编码的哈夫曼编码 */for (i=0; i<n; i++){printf ("%d 's Huffman code is: ", i);for (j=HuffCode[i].start+1; j < n; j++){printf ("%d", HuffCode[i].bit[j]);}printf(" start:%d",HuffCode[i].start);printf ("\n");}printf("Decoding?Please Enter code:\n");scanf("%s",&pp);decodeing(pp,HuffNode,n);getchar();return 0;
}

 

参考:

https://cloud.tencent.com/developer/article/1009606

https://baike.baidu.com/item/%E5%93%88%E5%A4%AB%E6%9B%BC%E6%A0%91


http://chatgpt.dhexx.cn/article/uRcnKf7S.shtml

相关文章

虚拟机下安装BackTrack5 (BT5)教程及BT5汉化

isare邀请您访问Backtrack中文网 http://www.backtrack.org.cn/?fromuid50397 isare邀请您访问Backtrack中文网 http://www.backtrack.org.cn/?fromuserisare PS&#xff1a;back track 安装过程中有2点要注意&#xff1a;第一&#xff1a;复制到99%的时候会等大约10来分钟&a…

bt 下载工具 deluge 配置 优化 使用

目录 Ubuntu 18 配置 deluge Deluge 安卓远程客户端 Deluge 性能调优 deluge是基于libtorrentpython的跨平台bt/pt客户端&#xff0c;适合在Linux环境下使用 deluge完全开源免费&#xff0c;对IPv6支持良好&#xff0c;性能优于transmission&#xff1b;在嵌入式设备上使用d…

BT5的U盘完整安装

BT5是什么就不用多说了&#xff0c;从网上看了许多教程&#xff0c;大多是利用unetbootin工具将ISO文件直接解压到U盘上&#xff0c;这样并不能完全使用BT&#xff0c;保存好的文件&#xff0c;重启机器后就没了&#xff0c;其实就是当做光盘使用了&#xff0c;另外还有一个方法…

有哪些好用的BT下载器?

​​​​​​2022年5个好用的 BT/ 磁力链接下载工具推荐 &#xff5c;Windows 、安卓系统 | 科技雷达 A full-featured download manager

BT是如何下载的

BT协议简介 一、BT下载是怎么来的&#xff1f; 在互联网上下载文件的方式大概有这么几种&#xff1a;FTP、HTTP、BT、eMule(电驴)等&#xff0c; 浏览器会直接支持FTP和HTTP下载&#xff0c;BT和eMule下载一般需要专用的下载软件的支持。 接下来分别简单介绍一下他们的区别&…

ed2k下载

ed2k下载 在下载ed2k资源的时候&#xff0c;浏览器一般不能直接下载&#xff0c;这个时候该怎么办呢&#xff1f; 方法一&#xff1a;下载迅雷&#xff0c;直接安装 方法二&#xff1a;使用在线工具&#xff0c;将链接转化为别的形式 https://tool.lu/urlconvert/ 方法三&am…

BT是怎么下载的

BT协议简介 一、BT下载是怎么来的? 在互联网上下载文件的方式大概有这么几种:FTP、HTTP、BT、eMule(电驴)等, 浏览器会直接支持FTP和HTTP下载,BT和eMule下载一般需要专用的下载软件的支持。 接下来分别简单介绍一下他们的区别: FTP 是 File Transfer Protocol(文件…

最好用的bt下载器qbittorrent下载安装使用教程

qBittorrent绝对是我心目中BT下载工具中的NO.1&#xff0c;虽说我平时也会用迅雷下载国内的某些资源&#xff0c;但是仍然不妨碍它是我心目中的主力下载神器&#xff01;它可以说是我最早接触的除迅雷之外的一款BT下载神器。它是完全免费的种子和磁力链接下载工具&#xff0c;最…

BT5 WIFI破解

实验环境 VMwareWorkstation 9.0 BackTrack5 R3-GNOME-32 工具说明 VMware&#xff1a;著名的虚拟机软件&#xff0c;本实验采用虚拟机环境下安装BackTrack。 BackTrack&#xff1a;是一个基于Ubuntu GNU/Linux的发行版本&#xff0c;主要用做数字取证和入侵测试。其无线安全审…

BT5下载地址

http://www.backtrack-linux.org/downloads/ 下载方法&#xff1a; 1,先填写好网页里的三个框,如: Your Name(你的名字): ABC Email Address(邮箱): ABC163.com Country(国家): china 2,然后点"download" 3,按照自己的…

最全BT介绍

BitTorrent 简介 riba2534 2021年04月11日 19:26 阅读 851 关注 BitTorrent 简介 从 P2P 说起 经常在网上飙车的老司机应该都知道 BT 下载&#xff0c;但是有时候拿到了种子却下载不动&#xff0c;会不会很抓狂&#xff0c;是不是还觉得是自己网不行&#xff0c;那作为一…

034_Unicode标准

1. Unicode标准 1.1. 由于ASCII字符集、ISO字符集、GBK字符集列出的字符集都有容量限制, 而且不兼容多语言环境, Unicode联盟开发了Unicode标准。 1.2. Unicode标准涵盖了世界上的所有字符、标点和符号。 1.3. 不论是何种平台、程序或语言, Unicode都能够进行文本数据的处理…

24.字符编码

1.字符编码 1.1简介 字符编码只与文本文件和字符串有关。 字符编码&#xff1a;记录人类字符与二进制数的对应关系。计算机只能识别二进制&#xff0c;但是通过字符编码可以展示出各式各样的语言字符。1.2发展过程 1.计算机是美国人发明的&#xff0c;为了能够让加计算机能够…

汉字编码

http://blog.csdn.net/zzidea/article/details/8497532 C语言编程&#xff0c;基本的类型有字符型&#xff0c;整数型&#xff0c;浮点型。这些类型是我们对事物进行描述所必不可少的东西。即基础&#xff0c;又非常核心。所以必须掌握。 一、 字符集 ASCII GB2…

《Qt5:键盘事件》

QKeyEvent类用来描述了一个键盘事件。常用的键盘事件有两种&#xff1a;按键按下和按键释放&#xff0c;一般按键按下事件用的多一点&#xff0c;下面为键盘按下和释放事件的声明&#xff1a; public:void keyPressEvent(QKeyEvent *event);void keyReleaseEvent(QKeyEvent *ev…

小伙 这样你就可以在Mac 中运行 Office 办公软件了

小伙 这样你就可以在Mac 中运行 Office 办公软件了 请参考以下步骤&#xff1a; 1、打开已经安装好的 CrossOver&#xff0c;点击“安装 Windows 应用程序”&#xff0c;在选择应用中的搜索框中输入“office”&#xff0c;接下来在下拉列表中会出现非常多的已经列出的相关软件&…

Unicode 编码表

正则查找: 中文文字中文符号表情符号... [^\x00-\xff] 其中 \x00-\xff 匹配 ASCII 代码中十六进制代码为 00-ff 的字符&#xff0c; 加个取反 ^ &#xff0c;则就表示表示匹配非单字节的字符&#xff0c;例如汉字&#xff0c;汉字符号等字符集。 中文文字&#xff08;简体繁体…

arduino学习笔记-库函数解析_LiquidCrystal_i2c使用说明以及lcd1602的驱动

LiquidCrystal_i2c是一个通过i2c驱动lcd显示屏的库函数&#xff0c;具体使用说明如下 i2c转接芯片的型号 PCA8574 arduino R3 A05 为 SCL A04 为 SDL 在头文件下要初始化对象 LiquidCrystal_I2C lcd(0x27,16,2); 对象名 lcd 可以任意&#xff0c;这关系到下面你使用方法…

Linux-Ubuntu系统 安装(重装)Mysql

一、检查服务器是否已有mysql &#xff08;如需自行下载jdbc相关包&#xff0c;例如mysql-connector等的有效网站&#xff1a;https://mvnrepository.com/artifact/mysql/mysql-connector-java/6.0.2&#xff09; 为确保后续没有权限错误&#xff0c;先切换到root用户权限&am…

HWP转Word说明

HWP&#xff0c;格式是韩国特有的文档格式&#xff0c;不能直接用MS Office打开或者直接转成Word&#xff0c;之前都是通过Hangul Viewer打印成XPS或PDF&#xff0c;再将文件转成Word&#xff0c;过程比较复杂&#xff0c;且Hangul Viewer打印时会自己在页脚处添加说明&#xf…