哈夫曼树的学习以及实践

news2025/1/22 9:05:30

哈夫曼树

  • 哈夫曼树的基本了解
  • 哈夫曼树的基本概念
  • 创建霍夫曼树的思路
  • 编码构建的思路
  • 代码实现
    • 创建HuffmanTree结点
    • 初始化HuffmanTree
    • 创建霍夫曼树
    • 霍夫曼树编码

哈夫曼树的基本了解

给定 n 个 权值 作为 n 个 叶子节点,构造一颗二叉树,若该树的 带权路径长度(WPL)达到最小,称这样的二叉树为 最优二叉树,也称为 哈夫曼树(Huffman Tree),还有的叫 霍夫曼树

哈夫曼树的基本概念

  1. 路径 :从树中的一个结点到达另一个节点的分支结构构成的两个点之间的路径
  2. 路径长度:路径上的分支的数目(例如根结点为第一层,叶子节点为L层,那么根结点到叶子结点之间的路径长度为L-1)
  3. **树的路径长度:**从树的根结点到每个结点的路径长度之和
  4. :若将树中节点赋给一个有着某种函数的数值,则这个数值称为该节点的 权
  5. 结点的带权路径长度:从该结点到树根之间路径长度与该结点权重的乘积
  6. 树的带权路径长度:树中所有的叶子结点的带权路径长度之和
    在这里插入图片描述

创建霍夫曼树的思路

赫夫曼编码也翻译为 哈夫曼编码(Huffman Coding),又称霍夫曼编码,是一种 编码方式,,属于一种 程序算法
赫夫曼编码是 赫哈夫曼树 在电讯通信中的经典的应用之一。
赫夫曼编码广泛地用于 数据文件压缩。其压缩率通常在 20%~90% 之间
赫夫曼码是 可变字长编码(VLC) 的一种。Huffman 于 1952 年提出一种编码方法,称之为最佳编码
根据已经构建完成的赫夫曼树,给各个字符规定编码(前缀编码):
向左的路径为 0
向右的路径为 1

编码构建的思路

请添加图片描述
请添加图片描述

代码实现

创建HuffmanTree结点

#pragma region HuffmanTree的结构定义
typedef int datatype;
typedef struct HuffmanTree
{
	int weight;/*权重*/
	datatype data;
	int parent;
	int leftchild;
	int rightchild;
}HTNode;
typedef HuffmanTree* HuffTree;
#pragma endregion

初始化HuffmanTree

HuffTree InitHuffTree(int TreeNum)
{
	/*初始化树:首先创建存放2*TreeNum的存储空间的树,然后0下标位置不存放数据,从1位置开始赋值权重以及数据。*/
	HuffTree HT = NULL;
	HT = (HuffTree)malloc(sizeof(HTNode)*(2 * TreeNum));/*下标为0的HuffmanTree的结点是不用的*/
	for (int i = 1; i < 2*TreeNum; i++)
	{
		HT[i].leftchild = -1;
		HT[i].rightchild = -1;
		HT[i].parent = -1;/*首先将双亲以及左右孩子置为-1*/
	}
	cout << "请输入权重" << endl;
	for (int i = 1; i <= TreeNum; i++)
	{
		cin >> HT[i].weight;/*对每个结点赋值权重*/
	}
	char c = getchar();
	cout << "请输入数据" << endl;
	for (int i = 1; i <=TreeNum; i++)
	{
		cin >> HT[i].data;
	}
	return HT;
}
#pragma endregion

创建霍夫曼树

void minvalue_select(HuffTree HT, int& minloction1, int& minloction2, int loc)
{
	int minvalue1 = MAXVALUE, minvalue2 = MAXVALUE;
	for (int i = 1; i < loc; i++)
	{
		if ((minvalue1 > HT[i].weight)&&(HT[i].parent == -1))
		{
			minloction2 = minvalue1;
			minloction2 = minloction1;
			minvalue1 = HT[i].weight;
			minloction1 = i;
		}
		else
		{
			if ((HT[i].weight <minvalue2)&&(HT[i].parent == -1))
			{
				minvalue2 = HT[i].weight;
				minloction2 = i;
			}
		}
	}
}
HuffTree CreatHuffmanTree(HuffTree HT,int TreeNum)
{
	/*最终的parent为-1的结点代表根结点 没有双亲*/
	if (HT == NULL)
	{
		cout << "HuffmanTree的数据为空 请重新输入" << endl;
		return NULL;
	}
	HuffTree tmpTree = NULL;
	tmpTree = HT;
	int minlocation1, minlocation2;
	for (int i = TreeNum+1; i <= TreeNum*2-1; i++)
	{
		minvalue_select(tmpTree, minlocation1, minlocation2, i-1);/*找出两个最小的值*/
		HT[minlocation1].parent = HT[minlocation2].parent = i;
		HT[i].leftchild = minlocation1;
		HT[i].rightchild = minlocation2;/*其中location2大于location1*/
		HT[i].weight = HT[minlocation1].weight + HT[minlocation2].weight;
	}
	/*此时i也就是最后一个根结点 它的左右孩子已经确定 但是它的parent为-1 表示它为根结点*/
	return HT;
}
#pragma endregion

霍夫曼树编码

#pragma region 从叶子结点到根结点逆向求HuffmanTree编码
typedef char** HuffmanCode;
void HuffmanCoding(HuffTree HT, HuffmanCode& HC, int TreeNum)
{
	HC = (HuffmanCode)malloc(sizeof(char*)*TreeNum);/*表明HC是一个指针类型的变量,同时每一个指针存放的位置为一个char*类型的数据,也就表示HC是一个存放指针类型数据的指针数组*/
	if (HT==NULL)
	{
		return;
	}
	char* tmpcode = (char*)malloc(sizeof(char)*TreeNum);
	if (tmpcode == NULL)
	{
		return;
	}
	tmpcode[TreeNum -1 ] = '\0';
	HuffTree  tmpHTree = NULL;
	tmpHTree = HT;
	for (int i = 1; i <= TreeNum; i++)
	{
		int location = TreeNum - 1;
		int parentIndex = tmpHTree[i].parent;
		int currentIndex = i;
		while (parentIndex !=-1)/*未到达根结点*/
		{
			if (tmpHTree[parentIndex].leftchild == currentIndex)
			{
				tmpcode[--location] = '0';
			}
			else
			{
				tmpcode[--location] = '1';
			}
			currentIndex = parentIndex;
			parentIndex = tmpHTree[parentIndex].parent;
		}
		/*完成编码*/
		HC[i] = (char*)malloc(sizeof(char)*(TreeNum-location));
		if (HC[i]!=NULL)
		{
			strcpy(HC[i], tmpcode + currentIndex);
		}
		cout << HC[i] << endl;
	}
	delete tmpcode;
}
#pragma endregion

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1446738.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue源码系列讲解——模板编译篇【二】(模板解析阶段)

目录 1. 整体流程 2. 回到源码 3. 总结 1. 整体流程 上篇文章中我们说了&#xff0c;在模板解析阶段主要做的工作是把用户在<template></template>标签内写的模板使用正则等方式解析成抽象语法树&#xff08;AST&#xff09;。而这一阶段在源码中对应解析器&…

读千脑智能笔记12_阻止人类灭绝

1. 阻止人类灭绝 1.1. 宇宙中唯一知道这些的物体&#xff0c;唯一知道宇宙存在的物体&#xff0c;是我们的大脑 1.2. 如果没有关于某个事物的知识&#xff0c;我们能说这个事物就一定存在吗&#xff1f; 1.2.1. 我们的大脑扮演着这样一个独特的角色&#xff0c;这很令人着迷…

宽带高效非对称连续J/F-1模式Doherty 功率放大器设计(2023.11 MTT)-从理论到ADS版图

宽带高效非对称连续J/F-1模式Doherty 功率放大器设计(2023.11 MTT)-从理论到ADS版图 这个文章实现的效果非常好&#xff0c;非常值得大家去阅读复现&#xff08;见前言介绍&#xff09;&#xff0c;但是我复现出现了一点困难&#xff0c;效果调不到那么好&#xff08;带宽只是…

家政小程序系统源码开发:引领智能生活新篇章

随着科技的飞速发展&#xff0c;小程序作为一种便捷的应用形态&#xff0c;已经深入到我们生活的方方面面。尤其在家庭服务领域&#xff0c;家政小程序的出现为人们带来了前所未有的便利。它不仅简化了家政服务的流程&#xff0c;提升了服务质量&#xff0c;还为家政服务行业注…

Linux--常用命令(详解)

详细目录 一、终端命令格式二、显示文件列表命令-ls2.1作用2.2格式2.3 ls常用选项2.3.1 ls -a2.3.2 ls -l(等价于 ll)2.3.2 ls -h 三、相对路径与绝对路径3.1绝对路径3.2相对路径 四、目录操作命令 -cd4.1作用4.2格式4.3案例4.3.1 cd -&#xff1a; 返回上一次所在目录4.3.2 cd…

Agile Initiative, Epic, and Story/Task

Stories, also called “user stories,” are short requirements or requests written from the perspective of an end user. stories are something the team can commit to finish within a one- or two-week sprint.Epics are large bodies of work that can be broken do…

Linux_进程间通信

管道 System V 共享内存 System V IPC 接口介绍 由于进程地址空间的存在&#xff0c;所以进程间有具有独立性&#xff0c;一个进程看不到另一个进程的数据。那么如果我们想让进程间通信&#xff0c;就必须先让它们先看到同一份资源。常见的进程间通信的方法有管道&#xff0c;…

ChatGpt报错:Your authentication token is no longer valid解决办法

今天打开ChatGpt突然提示Oops&#xff01;,Your authentication token is no longer valid.&#xff0c;之前还好好的&#xff0c;环境也没变啊&#xff0c;结果弄了好久终于解决&#xff0c;于是记录一下解决过程&#xff0c;顺便总结一下关于OpenAI各种报错的解决办法。 完整…

比较6*6范围内8个点425个结构的顺序

( A, B )---6*30*2---( 1, 0 )( 0, 1 ) 让网络的输入有6个节点&#xff0c;训练集AB各由6张二值化的图片组成&#xff0c;让A中有8个点&#xff0c;让B全是0&#xff0c;收敛误差7e-4&#xff0c;收敛199次&#xff0c;统计迭代次数平均值并排序。 假设这个6*6的结构的行和列都…

JavaWeb:SpingBoot原理 --黑马笔记

1. 配置优先级 在我们前面的课程当中&#xff0c;我们已经讲解了SpringBoot项目当中支持的三类配置文件&#xff1a; application.properties application.yml application.yaml 在SpringBoot项目当中&#xff0c;我们要想配置一个属性&#xff0c;可以通过这三种方式当中…

每日一练:LeeCode-617、合并二叉树【二叉树+DFS】

本文是力扣LeeCode-617、合并二叉树【二叉树DFS】 学习与理解过程&#xff0c;本文仅做学习之用&#xff0c;对本题感兴趣的小伙伴可以出门左拐LeeCode。 给你两棵二叉树&#xff1a; root1 和 root2 。 想象一下&#xff0c;当你将其中一棵覆盖到另一棵之上时&#xff0c;两…

力扣面试题 16.21. 交换和(哈希表)

Problem: 面试题 16.21. 交换和 文章目录 题目描述思路及解法复杂度Code 题目描述 思路及解法 1.分别求取array1与array2数组每一个元素的和&#xff08;sum1与sum2&#xff09;并同时将array2的元素存入一个set集合中&#xff1b; 2.如果sum1和sum2的和为奇数&#xff0c;则不…

深度学习基础之《深度学习介绍》

一、深度学习与机器学习的区别 1、特征提取方面 机器学习&#xff1a;人工特征提取 分类算法 深度学习&#xff1a;没有人工特征提取&#xff0c;直接将特征值传进去 &#xff08;1&#xff09;机器学习的特征工程步骤是要靠手工完成的&#xff0c;而且需要大量领域专业知识…

浅谈进制的转换

本文创作灵感来自CSDN咸鱼WCY 的 咸鱼小白学嵌入式之C语言&#xff08;2.进制&#xff09; 博主更完就没更了&#xff0c;决定书接上回&#xff08;喜 进制是个啥 要理解进制&#xff0c;首先哈&#xff0c;咱得知道不同进制的含义 说到底&#xff0c;各个进制其实有点像在…

Hive SQL编译成MapReduce任务的过程

一、 Hive 底层执行架构 1&#xff09; Hive简介 Hive是Facebook实现的一个开源的数据仓库工具。将结构化的数据文件映射为数据库表&#xff0c;并提供HQL查询功能&#xff0c;将HQL语句转化为MapReduce任务运行 2&#xff09; Hive本质&#xff1a;将 HQL 转化成 MapReduce 程…

Java 基于 SpringBoot+Vue 的社区医院系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

26. 可变参数和Collection集合工具类

可变参数与Collections 1. 可变参数1. 概述2. 格式3. 代码示例4. 注意事项 2. Collections集合工具类2.1 概述2.2 方法2.3 代码示例2.4 注意事项 1. 可变参数 1. 概述 可变参数&#xff08;Variable Arguments&#xff09;是指在参数列表中允许传入不定个数的参数。在许多编程…

多模态论文串讲·上【论文精读·46】只用 Transformer encoder 的一些方法viLT、clip、ALBEF、VLMO

目录 简单回顾一下 viLT 简单回顾CLIP 总结后提出改进 1 ALBEF 1.1 主体方法 1.1.1 模型结构 1.1.2 目标函数 1 ITCloss&#xff1a;align before fuse的align 2 ITM loss 3 MLM loss 1.1.3 动量蒸馏 1.2 预训练数据集 1.3 下游任务描述 1.4 实验结果 1 消融实验…

洛谷: [CSP-J 2023] 小苹果

题目描述 小 Y 的桌子上放着 n n n 个苹果从左到右排成一列&#xff0c;编号为从 1 1 1 到 n n n。 小苞是小 Y 的好朋友&#xff0c;每天她都会从中拿走一些苹果。 每天在拿的时候&#xff0c;小苞都是从左侧第 1 1 1 个苹果开始、每隔 2 2 2 个苹果拿走 1 1 1 个苹果…

【JAVA WEB】JavaScript--函数 作用域 对象

目录 函数 语法格式 示例 定义没有参数列表&#xff0c;也没有返回值的一个函数 定义一个有参数列表 &#xff0c;有返回值的函数 关于参数个数 函数表达式 作用域 作用域链 对象 基本概念 创建对象 1.使用 字面量 创建对象 2.使用new Object()创建对象 3.使…