哈夫曼树的学习以及实践

哈夫曼树

  • 哈夫曼树的基本了解
  • 哈夫曼树的基本概念
  • 创建霍夫曼树的思路
  • 编码构建的思路
  • 代码实现
    • 创建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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言第二十三弹---指针(七)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 指针 1、sizeof和strlen的对比 1.1、sizeof 1.2、strlen 1.3、sizeof 和 strlen的对比 2、数组和指针笔试题解析 2.1、⼀维数组 2.2、二维数组 总结 1、si…

C语言每日一题(56)平衡二叉树

力扣网 110 平衡二叉树 题目描述 给定一个二叉树&#xff0c;判断它是否是高度平衡的二叉树。 本题中&#xff0c;一棵高度平衡二叉树定义为&#xff1a; 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,…

牛客错题整理——C语言(实时更新)

1.以下程序的运行结果是&#xff08;&#xff09; #include <stdio.h> int main() { int sum, pad,pAd; sum pad 5; pAd sum, pAd, pad; printf("%d\n",pAd); }答案为7 由于赋值运算符的优先级高于逗号表达式&#xff0c;因此pAd sum, pAd, pad;等价于(…

Linux系统之部署File Browser文件管理系统

Linux系统之部署File Browser文件管理系统 一、File Browser介绍1.1 File Browser简介1.2 File Browser功能1.3 File Browser使用场景 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、检查本地环境3.1 检查本地操作系统版本3.2 检查系统内核版本 四、安装File Browser4…

Linux_线程

线程与进程 多级页表 线程控制 线程互斥 线程同步 生产者消费者模型 常见概念 下面选取32位系统举例。 一.线程与进程 上图是曾经我们认为进程所占用的资源的集合。 1.1 线程概念 线程是一个执行分支&#xff0c;执行粒度比进程细&#xff0c;调度成本比进程低线程是cpu…

SpringCloud-Eureka服务注册中心测试实践

5. Eureka服务注册中心 5.1 什么是Eureka Netflix在涉及Eureka时&#xff0c;遵循的就是API原则.Eureka是Netflix的有个子模块&#xff0c;也是核心模块之一。Eureka是基于REST的服务&#xff0c;用于定位服务&#xff0c;以实现云端中间件层服务发现和故障转移&#xff0c;服…

fast.ai 深度学习笔记(六)

深度学习 2&#xff1a;第 2 部分第 12 课 原文&#xff1a;medium.com/hiromi_suenaga/deep-learning-2-part-2-lesson-12-215dfbf04a94 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 来自 fast.ai 课程的个人笔记。随着我继续复习课程以“真正”理解它&#xff0c;…

Java 基于微信小程序的私家车位共享系统

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

LC 987. 二叉树的垂序遍历

987. 二叉树的垂序遍历 难度 : 困难 题目大意&#xff1a; 给你二叉树的根结点 root &#xff0c;请你设计算法计算二叉树的 垂序遍历 序列。 对位于 (row, col) 的每个结点而言&#xff0c;其左右子结点分别位于 (row 1, col - 1) 和 (row 1, col 1) 。树的根结点位于 …

爬虫2—用爬虫爬取壁纸(想爬多少张爬多少张)

先看效果图&#xff1a; 我这个是爬了三页的壁纸60张。 上代码了。 import requests import re import os from bs4 import BeautifulSoupcount0 img_path "./壁纸图片/"#指定保存地址 if not os.path.exists(img_path):os.mkdir(img_path) headers{ "User-Ag…

【STL】string的模拟实现

string类的模拟实现 一、接口函数总览二、默认成员函数1、构造函数2、拷贝构造函数&#xff08;1&#xff09;写法一&#xff1a;传统写法&#xff08;2&#xff09;写法二&#xff1a;现代写法 3、赋值运算符重载函数&#xff08;1&#xff09;写法一&#xff1a;传统写法&…

【开源】JAVA+Vue.js实现天然气工程运维系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统角色分类2.2 核心功能2.2.1 流程 12.2.2 流程 22.3 各角色功能2.3.1 系统管理员功能2.3.2 用户服务部功能2.3.3 分公司&#xff08;施工单位&#xff09;功能2.3.3.1 技术员角色功能2.3.3.2 材料员角色功能 2.3.4 安…

东风联手华为打造首款SUV,车长超5米,配纯电和增程双动力系统

在上个月&#xff08;2024年1月份&#xff09;&#xff0c;东风汽车和华为达成了战略合作计划&#xff0c;两家品牌将联手打造全新的汽车品牌——奕派汽车&#xff0c;而目前我们从相关渠道获悉&#xff0c;其首款SUV车型已经获得了实拍亮相&#xff0c;而新车的内部代号为S59&…

MySQL篇----第十四篇

系列文章目录 文章目录 系列文章目录前言一、MySQL 数据库作发布系统的存储,一天五万条以上的增量,预计运维三年,怎么优化?二、锁的优化策略三、索引的底层实现原理和优化四、什么情况下设置了索引但无法使用前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽…

Java使用opencsv完成对csv批量操作

文章目录 前言一、maven二、造数三、代码部分1.OpenCsvController2.OpenCsvUtil3.StudentInfo4.CodeToValue 三、效果展示1.download2.upload 总结 前言 csv文件是不同于excel文件的另一种文件&#xff0c;常常以,作为分隔符&#xff0c;本篇将通过JavaBean的形式完成对csv文件…

《Git 简易速速上手小册》第2章:理解版本控制(2024 最新版)

文章目录 2.1 本地仓库与版本历史2.1.1 基础知识讲解2.1.2 重点案例&#xff1a;回滚错误提交2.1.3 拓展案例 1&#xff1a;利用 git bisect 查找引入 bug 的提交2.1.4 拓展案例 2&#xff1a;合并提交历史 2.2 远程仓库的使用2.2.1 基础知识讲解2.2.2 重点案例&#xff1a;在 …

CSP-动态规划-最长公共子序列(LCS)

一、动态规划 动态规划&#xff08;Dynamic Programming&#xff0c;简称DP&#xff09;主要用于求解可以被分解为相似子问题的复杂问题&#xff0c;特别是在优化问题上表现出色&#xff0c;如最短路径、最大子数组和、编辑距离等。动态规划的核心思想是将原问题分解为较小的子…

Old Money 和 New Money

&#xff08;1&#xff09; 我想借用一下&#xff1a;Old Money 和 New Money这两个词&#xff0c;但不是欧洲那种Old Money 和 New Money的定义。 我定义的Old Money是&#xff1a; 人脉关系、资源 信息差、成本差 我定义的New Money是&#xff1a; 科技是第一生产力 2015年以…

计算机网络——09Web-and-HTTP

Web and HTTP 一些术语 Web页&#xff1a;由一些对象组成对象可以是HTML文件、JPEG图像&#xff0c;JAVA小程序&#xff0c;声音剪辑文件等Web页含有一个基本的HTML文件&#xff0c;该基本HTML文件又包含若干对象的引用&#xff08;链接&#xff09;通过URL对每个对象进行引用…

程序员与电脑:不眠之夜的背后故事

在这个数字化飞速发展的时代&#xff0c;程序员和他们的电脑成了不可分割的伙伴。 如果你有机会深夜走过城市的某个角落&#xff0c;透过窗户瞥见那些亮着的电脑屏幕&#xff0c;你可能会好奇&#xff1a;这些电脑为什么总是开着的&#xff1f; 难道程序员们都有失眠症吗&…