当前位置: 首页 > article >正文

哈夫曼树和哈夫曼编码与译码

Huffman树的创建

思想概述

为求得最优二叉树,哈夫曼巧妙地涉及到哈夫曼算法。通过哈夫曼算法可以建立一棵哈夫曼树。现有n个结点,如果岸边每个结点都作为一棵二叉树的根结点,那么这个n个根结点就组成了一个森林。把结点在文件中出现的次数定义为该结点的权值。

1.在森林中取权值最小的两个根结点,合并成一棵二叉树,并生成一个新结点T,作为这两个结点的父亲,T的权值是它的两个子结点的权值之和。与此同时,森林中减少了一棵树。

2.对新森林重复上述操作,直至森林中只有唯一的根结点,最后的根结点便是所求的哈夫曼树的根。

注意:最优二叉树未必唯一,而哈夫曼树可能只是满足条件的所有最优二叉树中的一棵。

Huffman结点

假定哈夫曼树中每个结点的结构为:

LLINK/左链接INFO/信息域Weight/权值RLINK/右链接
/*Huffman结点结构体*/
typedef struct HuffmanNode {
	char INFO;  //信息域
	int Weight;  //权重
	HuffmanNode* LLINK;  //左链接
	HuffmanNode* RLINK;  //右链接
}HuffmanNode;

Huffman树

假定与给定的m个权值结合的结点的地址存在于一维数组H[1:m+1]中,并且该数组按每个结点的Weight域已排序(从小到大)。

如Huffman树结点声明所示,其中H为存储Huffman结点的一维数组(Huffman结点内存储了结点权值Weight),且数组H已排序。

/*Huffman树结构体*/
typedef struct HuffmanTree {
	HuffmanNode** H;  //存储Huffman结点的数组
	int m;  //结点个数
}HuffmanTree;

构建Huffman树 

1.初始化

创建所有结点,把每个结点都作为一棵二叉树的根结点,所有结点组成一个森林 。

2.组合

在森林中选取两个最小的结点,合并成一棵二叉树,并并生成一个新结点T,作为这两个结点的父亲,T的权值是它的两个子结点的权值之和。

3.找位置

找到H数组中合适的位置插入新生成的二叉树,使数组保持递增。

4.循环

循环操作所有结点。

HuffmanTree* CreateHuffmanTree(char data[],int weight[],int n) {
	//初始化
	HuffmanTree* tree = new HuffmanTree;
	tree->m = n;
	//每个结点都作为一棵树的根结点,组成森林
	for (int i = 1; i <= tree->m; i++) {
		tree->H[i] = new HuffmanNode;
		tree->H[i]->INFO = data[i];
		tree->H[i]->Weight = weight[i];
		tree->H[i]->LLINK = NULL;
		tree->H[i]->RLINK = NULL;
	}
	//组合过程
	HuffmanNode* p1, * p2,* p,* t;
	int i, j;
	for (i = 1; i < tree->m; i++) {
		t = new HuffmanNode;
		p1 = tree->H[i];
		p2 = tree->H[i + 1];
		t->LLINK = p1;
		t->RLINK = p2;  //链接左右结点
		t->Weight = p1->Weight + p2->Weight;  //权重等于子结点权重之和
		p = t;
		j = i + 2;  //从下一棵结点开始比较
		if (j <= tree->m && p->Weight >= tree->H[j]->Weight) {  //寻找合适的位置,使森林保持递增
			tree->H[j - 1] = tree->H[j];  //小的结点前移,给p结点腾位置
			j++;
		}
		tree->H[j - 1] = p;
	}
	return tree;
}

Huffman编码 

对于所有的编码,哈夫曼编码是文件的总编码长度最短,字符集中的字符所在的结点均是哈夫曼树中的外结点。

将哈夫曼树每个分支结点的左分支标上0,右分支标上1,把从根结点到每个叶结点的路径上的标号连接起来,作为该叶结点所代表的字符的编码。

/*Huffman编码*/
#include <unordered_map>
#include <cstring>
//使用unordered_map,char标志字符,string对应的Huffman编码
typedef unordered_map<char, string> UMCS;
UMCS HuffmanCode;  //Huffman编码
void CreateHuffmanCode(HuffmanNode* t,string code) {
	if (t == NULL) return;
	//左右子结点为空,则为叶结点,为字符
	if (t->LLINK == NULL && t->RLINK == NULL) {
		HuffmanCode[t->INFO] = code;
	}
	//递归处理左右结点,进行Huffman编码
	CreateHuffmanCode(t->LLINK, code + "0");  //左结点,+"0"
	CreateHuffmanCode(t->RLINK, code + "1");  //右结点,+"1"
}

Huffman译码

对压缩后的数据文件进行解码的过程是,依次读入文件的二进制码,从哈夫曼树的根结点出发,若当前读入0,则走向其左儿子,否则走向其右儿子,到达某一叶结点时,便可以译出相应的字符。

/*Huffman译码*/
void TransHuffmanCode(HuffmanNode* root) {
	HuffmanNode* t=root;
	string ans="";  //存储最终译码结果
	string code;  
	cin >> code;  //读入二进制Huffman编码
	int n = code.size();  //二进制编码的长度
	for (int i = 0; i < n; i++) {
		char ch = code[i];  
		if (ch == '0') t = t->LLINK;  //读入'0',则走左分支
		if (ch == '1') t = t->RLINK;  //读入'1',则走右分支
		//若走到叶结点,当前阶段译码成功,可存入一个字符
		if (t->LLINK == NULL && t->RLINK == NULL) {  
			ans = ans + t->INFO;  //串入译码结果
			if (i != n - 1) t = root;  //若此时还剩二进制编码未译,回到根结点,继续译码
		}
		
	}
	//若二进制编码读入完全,此时却没有走到叶结点,证明译码不完全,译码错误
	if (!(t->LLINK == NULL && t->RLINK == NULL))
		cout << "INVALID" << endl;  //译码错误,输出"INVALID"
	else
		cout << ans<<endl;  //译码成功,输出最终译码结果
}

《数据结构》刘大友||第5章 树与二叉树||5.4压缩与哈夫曼树 


http://www.kler.cn/a/382938.html

相关文章:

  • C语言 循环高级
  • 为什么要学习 Java 编程
  • Flutter鸿蒙next 状态管理框架对比分析
  • DataX 的安装配置和使用 (详细版)
  • LabVIEW气体检测系统
  • Memento 备忘录模式
  • 《ASP.Net Core技术内幕与项目实战》读书笔记1
  • 全平台设置jetbrains mono字体
  • #渗透测试#SRC漏洞挖掘# 操作系统-Linux系统基础02之Openssl、软连接与硬连接、用户账号数据库
  • HiveMetastore 的架构简析
  • Node.js回调函数以及事件循环使用介绍(基础介绍 三)
  • spring-boot(thymeleaf前端框架,简单了解)、( 跨域请求)
  • 玩转「HF/魔搭/魔乐」平台
  • 解决 Ubuntu ‘InRelease is not valid yet’ 报错:内网源 apt update 详细教程
  • 端侧小模型新星,SmolLM2 1.7B击败了Llama 3.2、Qwen 2.5
  • 基础算法练习--滑动窗口(日更中)
  • 青少年编程与数学 02-003 Go语言网络编程 12课题、Go语言Soket编程
  • RabbitMQ 管理平台(控制中心)的介绍
  • SpringBoot健身房管理:提升效率与体验
  • STM32中,在哪些时候需要配置复用推挽/开漏输出?
  • 3种方法轻松从硬盘恢复已删除文件!
  • 零基础学习Java AI Spring AI
  • 舜宇光学科技入职测评:北森商业推理40分钟28题真题解析、网盘资料下载、答题技巧
  • stable diffusion 大模型
  • 腾讯轻量云服务器docker拉取不到镜像的问题:拉取超时
  • 如何不封禁UDP协议同时防止UDP攻击