【GDPU】数据结构实验十 哈夫曼编码

【实验内容】


1、假设用于通信的电文仅由8个字母 {a, b, c, d, e, f, g, h} 构成,它们在电文中出现的概率分别为{ 0.07, 0.19, 0.02, 0.06, 0.32, 0.03, 0.21, 0.10 },试为这8个字母设计哈夫曼编码。

提示:包含两个过程:1)构建哈夫曼树,(2)输出编码。


我的思路:

1建造哈夫曼树的过程直接按照哈夫曼思想模拟即可

2)输出编码。而 哈夫曼编码函数,我使用了 图论中的 dfs回溯算法 的思想,采用以 递归为 核心的方法遍历整棵树,并将走过的左路径标记为 0,将走过的右路径标记为 1,到了叶子节点收集路径结果,

每一条路径我使用 一维数组 path 记录

全部路径的结果,我使用 二维数组 result 存储

最后打印 result  数组即可


简而言之:

用一维数组记录路径 上的 0 和 1,到了叶子节点就成为一条完整的编码

将每一条编码用  二维数组 存起来


头文件 Head.h

建造一棵哈夫曼树的相关函数和操作

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define MAX 40// 创建树节点
typedef struct HtNode {int ww;int parent, Lchild, Rchild;
}HtNode;// 哈夫曼树结构
typedef struct HtTree {int root;HtNode ht[MAX];
}PHtTree;// 构造哈夫曼树
// m 为权值节点数量,w 为权值数组
PHtTree* CreateHuffMan(int m, int* w) {// 创建带有 m 个叶子节点的哈夫曼树PHtTree* pht = (PHtTree*)malloc(sizeof(PHtTree));if (pht == NULL) {perror("malloc fail !");return NULL;}// 初始化for (int i = 0; i < 2 * m - 1; ++i) {pht->ht[i].Lchild = pht->ht[i].Rchild = pht->ht[i].parent = -1;// 将数组前 m 个位置放入 权值数组元素if (i < m)pht->ht[i].ww = w[i];elsepht->ht[i].ww = -1;}// 构建哈夫曼树int i;for (i = 0; i < m - 1; i++) {// 两个m 找最小权值,两个 index 记录这两节点的下标int m1, m2, index1, index2;m1 = m2 = INT_MAX;index1 = index2 = -1;// 每轮都在区间 [0,  m + i] 找两个最小权值节点,且没有父节点(即没有使用过)for (int j = 0; j < m + i; ++j) {if (pht->ht[j].ww < m1 && pht->ht[j].parent == -1) {m2 = m1;index2 = index1;m1 = pht->ht[j].ww;index1 = j;}else if (pht->ht[j].ww < m2 && pht->ht[j].parent == -1) {m2 = pht->ht[j].ww;index2 = j;}}// 找到节点之后,构建父节点,并将父节点放进数组中pht->ht[index1].parent = m + i;pht->ht[index2].parent = m + i;pht->ht[m + i].ww = m1 + m2;pht->ht[m + i].Lchild = index1;pht->ht[m + i].Rchild = index2;}pht->root = m + i; // 更新根节点:m+i 即为 m + (m-2)return pht;
}

哈夫曼编码函数  HuffmanEncode

#include"Head.h"// 哈夫曼编码
// 思路:遍历每一条路,到叶子节点记录结果,左边标记为 0, 右边标记为 1// p  遍历 path :从下标 1 开始存放编码串,下标 0 存放字符串长度(表示该编码串长度,方便遍历)
// r 遍历 result:代表一一存放结果
int r = 0, p = 1;  
int result[MAX][MAX];  // 收集 path 的每一次结果
int path[MAX];   // 记录每一条路径的编码void HuffmanEncode(HtNode* ht, int root)
{if (root == -1) return; // 空节点返回if (ht[root].Lchild == -1 && ht[root].Rchild == -1) { // 叶子节点 就记录结果path[0] = p - 1;  // p-1 代表此时 path数组中收集的 路径上的(一串 1 和 0)的数量:方便遍历,因为每一串编码不等长,所以需要记录数量memcpy(result + r, path, sizeof(int)*p);  // 将一维数组 path 存放进二维数组 result :记录每一条路径的最终结果r++;path[0] = 0;  // 将第 0 个位置重新置为 0(表示恢复之前的状态)return;}path[p++] = 0;  // 向左走路径标记为 0HuffmanEncode(ht, ht[root].Lchild); // 递归到左节点p--;  // 从左节点回退回来:p-- 代表将 path[p++] = 0;   这里曾经标记的 0 给"删除"path[p++] = 1;  // 路径标记为 1HuffmanEncode(ht, ht[root].Rchild); // 递归到右节点p--;   // 从右节点回退回来:p-- 代表将 path[p++] = 1;   这里曾经标记的 1 给"删除"}

主函数 Main.c 

int main()
{// 输入 m 和 w 数组int m, w[MAX];scanf("%d", &m);float t = 0;for (int i = 0; i < m; ++i) {scanf("%f", &t);w[i] = t * 100;  // 浮点树先乘上倍数,变成整型,方便计算}// 构建一棵树PHtTree* pht = CreateHuffMan(m, w);HuffmanEncode(pht->ht, pht->root - 1); // 传数组过去就可以了// 打印每一编码printf("\n");for (int i = 0; i < m; ++i) {int x = result[i][0];for (int j = 1; j <= x; ++j) {printf("%d ", result[i][j]);}printf("\n");}return 0;
}

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

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

相关文章

【iOS】——浅析CALayer

文章目录 一、CALayer介绍二、UIview与CALayer1.区别2.联系 三、CALayer的使用1.初始化方法2.常用属性 四.CALayer坐标系1.position属性和anchorPoint属性2.position和anchorPoint的关系3.position、anchorPoint和frame的关系 五、CALayerDelegate六、CALayer绘图机制1.绘图流程…

利用Jenkins完成Android项目打包

问题和思路 目前存在的问题 打包操作由开发人员完成&#xff0c;这样开发进度容易被打断。 解决问题的思路 将打包操作交测试/产品/开发人员来完成&#xff0c;主要是测试/开发。 按照以上的思路&#xff0c;那么JenkinsGradle的解决方案是比较经济的&#xff0c;实现起来…

鸿蒙内核源码分析(互斥锁篇) | 互斥锁比自旋锁丰满多了

内核中哪些地方会用到互斥锁?看图: 图中是内核有关模块对互斥锁初始化,有文件,有内存,用消息队列等等,使用面非常的广.其实在给内核源码加注的过程中,会看到大量的自旋锁和互斥锁,它们的存在有序的保证了内核和应用程序的正常运行.是非常基础和重要的功能. 概述 自旋锁 和…

5.7 线程

进程&#xff1a;解耦稳定&#xff0c;内容之间是不相关的&#xff0c;通信不便利&#xff0c;理论上进程的软硬件的切换时间以及创建开销非常大。--------》资源共享线程实现 线程的问题&#xff1a;本质就是不解耦&#xff0c;一个出问题别的就很有可能出问题&#xff0c;同…

Scanner中next()、nextInt()、nextLine()、hasNext()、hasNextInt()的使用方法及注意事项

目录 1、next()、nextInt()、nextLine()的使用方法及区分 2、循环时如何使用hasNext方法 3、用hasNextInt()作为判断下一个输入是否为数字需要配合next()方法使用 1、next()、nextInt()、nextLine()的使用方法及区分 三者简单定义 next()&#xff1a;此方法遇见第一个有效字符…

使用AIGC生成软件类图表

文章目录 如何使用 AI 生成软件类图表什么是 MermaidMermaid 的图片如何保存&#xff1f;mermaid.liveDraw.io Mermaid可以画什么图&#xff1f;流程图时序图 / 序列图类图状态图甘特图实体关系图 / ER图 如何使用 AI 生成软件类图表 ChatGPT 大语言模型不能直接生成各类图表。…

linux系统下产生Segmentation fault 与 Segmentation fault (core dumped)!!!

最近在学习的过程中&#xff0c;遇到了Segment fault&#xff08;段错误&#xff09;的问题&#xff0c;经过一番查找资料&#xff0c;学到了一些相关知识&#xff0c;这里做一个梳理&#xff0c;以防以后在遇到类似的问题&#xff0c;并且希望能够帮助到大家一丝丝&#xff01…

python中numpy库使用

array数组 生成array数组 将list转化为array数组 import numpy as np np.array([1,2],typenp.int32)其中dtype定义的是元素类型&#xff0c;np.int32指32位的整形 如果直接定义dtypeint 默认的是32位整形。 zeors和ones方法 zeros()方法&#xff0c;该方法和ones()类似&a…

有什么方便实用的成人口语外教软件?6个软件教你快速进行口语练习

有什么方便实用的成人口语外教软件&#xff1f;6个软件教你快速进行口语练习 口语能力在语言学习中占据着重要的位置&#xff0c;因为它直接关系到我们与他人进行交流和沟通的效果。为了提高口语能力&#xff0c;很多成人选择通过外教软件进行口语练习&#xff0c;这些软件提供…

GNU Radio FFT模块结合stream to vector应用及Rotator频偏模块使用

文章目录 前言一、FFT 模块应用1、stream to vector 介绍2、创建 grc 图测试3、运行结果 二、频偏模块1、Rotator 简介2、创建 grc 图测试3、运行结果 前言 写个博客记录一下自己的蠢劲儿&#xff0c;之前我想用 FFT 模块做一些信号分析的东西&#xff0c;官方的 FFT 模块必须…

营销5.0时代,企业的痛如何解?

进入营销5.0阶段之后&#xff0c;许多企业都需解决连接客户效能低下的问题。针对这个问题&#xff0c;产品经理、软件开发公司包括个人开发者&#xff0c;要怎么找到有效的“解药”&#xff1f; 营销不仅每年都在变化&#xff0c;甚至每天都在变化。 ——现代营销学之父&…

【再探】设计模式—适配器、装饰及外观模式

结构型设计模式是用于设计对象和类之间关系的一组设计模式。一共有7种&#xff1a;适配器模式、装饰器模式、外观模式、桥接模式、组合模式、享元模式及代理模式。 1 适配器模式 需求&#xff1a;在软件维护阶段&#xff0c;已存在的方法与目标接口不匹配&#xff0c;需要个中…

论文阅读:RHO-1:Not All Tokens Are What You Need 选择你需要的 Tokens 参与训练

论文链接&#xff1a;https://arxiv.org/abs/2404.07965 以往的语言模型预训练方法对所有训练 token 统一采用 next-token 预测损失。作者认为“并非语料库中的所有 token 对语言模型训练都同样重要”&#xff0c;这是对这一规范的挑战。作者的初步分析深入研究了语言模型的 t…

记录一个练手的js逆向password

很明显 请求加密了password 全局搜索 有个加密函数(搜不到的可以搜临近的其他的关键字 或者url参数) 搜索的时候一定要仔细分析 我就没有仔细分析 我搞了好久 又是xhr又是hook的(还没hook到) 我当时也是疏忽了 我寻思这个也不是js文件 直到后来 我怎么也找不到 我就猜想 不…

代码随想录算法训练营DAY44|C++动态规划Part6|完全背包理论基础、518.零钱兑换II、377. 组合总和 Ⅳ

文章目录 完全背包理论基础完全背包问题的定义与01背包的核心区别为什么完全背包的循环顺序可以互换&#xff1f;CPP代码 ⭐️518.零钱兑换II思路CPP代码 ⭐️377. 组合总和 Ⅳ思路CPP代码 扩展题 完全背包理论基础 卡码网第52题 文章链接&#xff1a;完全背包理论基础 视频链接…

【数据结构与算法】力扣 102. 二叉树的层序遍历

题目描述 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例 1&#xff1a; 输入&#xff1a; root [3,9,20,null,null,15,7] 输出&#xff1a; [[3],[9,20],[15,7]]示例 2&#x…

上证50etf期权到底该怎么玩?

今天期权懂带你了解上证50etf期权到底该怎么玩&#xff1f;ETF期权是一种股票市场上的金融衍生品&#xff0c;它是在交易所上市交易的期权合约&#xff0c;其标的资产是某个特定的交易所交易基金&#xff08;ETF&#xff09;&#xff0c;如上证50指数ETF或沪深300指数ETF等。 上…

Git命令Gitee注册idea操作git超详细

文章目录 概述相关概念下载和安装常见命令远程仓库介绍与码云注册创建介绍码云注册远程仓库操作关联拉取推送克隆 在idea中使用git集成add和commit差异化比较&查看提交记录版本回退及撤销与远程仓库关联 push从远程仓库上拉取&#xff0c;克隆项目到本地创建分支切换分支将…

(✌)粤嵌—2024/5/7—除自身以外数组的乘积

代码实现&#xff1a; /*** Note: The returned array must be malloced, assume caller calls free().*/ int* productExceptSelf(int *nums, int numsSize, int *returnSize) {// 左乘积int l[numsSize];l[0] 1;for (int i 1; i < numsSize; i) {l[i] l[i - 1] * nums[…

Cesium学习——渲染、加载GeoJSON、调整位置

渲染概述 作者&#xff1a;当时明月在曾照彩云归 出处&#xff1a;https://www.cnblogs.com/jiujiubashiyi/p/17124717.html 1. 引言 Cesium是一款三维地球和地图可视化开源JavaScript库&#xff0c;使用WebGL来进行硬件加速图形&#xff0c;使用时不需要任何插件支持&#xf…