【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.hqwc.cn/news/675220.html

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

相关文章

C语言实现面向对象—以LED驱动为例

点亮一个LED 常见的LED代码 分层分离思想 面向对象的LED驱动 LED左边高电平。 当LED右边为低电平时&#xff0c;LED有电流通过&#xff0c;LED亮。反之&#xff0c;LED灭 GPIO功能描述&#xff1a; 点亮LED的步骤及代码&#xff1a; 开启GPIO的时钟 配置GPIO为输出模式 …

04-22 周日 阿里云-瑶光上部署FastBuild过程(配置TLS、自定义辅助命令)

04-22 周日 阿里云-瑶光上部署FastBuild过程 时间版本修改人描述2024年4月22日14:18:59V0.1宋全恒新建文档2024年4月23日20:41:26V1.0宋全恒完成了基本流程的添加 简介 前提 准备两台服务&#xff0c;一台部署Docker&#xff0c;一台部署FastBuild的镜像容器服务所述的Docke…

stm32f103zet6_DAC_2_输出电压

实现效果 DAC输出的电压 同过电压表测量电压 1.DAC配置的步骤 初始化DAC时钟。配置DAC的GPIO端口。设置DAC的工作模式&#xff08;例如&#xff0c;是否使用触发功能&#xff0c;是否启用DAC中断等&#xff09;。启动DAC。 2常用的函数 函数 HAL_DAC_Start() - 开启指定…

软件系统概要设计说明书(实际项目案例整理模板套用)

系统概要设计说明书 1.整体架构 2.功能架构 3.技术架构 4.运行环境设计 5.设计目标 6.接口设计 7.性能设计 8.运行设计 9.出错设计 全文档获取进主页 软件资料清单列表部分文档&#xff08;全套可获取&#xff09;&#xff1a; 工作安排任务书&#xff0c;可行性分析报告&…

阿里巴巴alibaba国际站API接口:商品详情和关键词搜索商品列表

阿里巴巴国际站&#xff08;Alibaba.com&#xff09;提供了API接口供开发者使用&#xff0c;以实现与平台的数据交互。然而&#xff0c;由于API的详细内容和调用方式可能会随着时间和平台更新而发生变化&#xff0c;以下是一个概述和一般性的指导&#xff0c;关于如何使用阿里巴…

如何让CANoe或Wireshark自动解析应用层协议

当我们使用CANoe软件或Wireshark工具抓取以太网总线上的报文时,网卡首先会把以太网总线上的模拟信号解析成以太网帧数据。数据链路层根据二层头部中的Type字段值确定上层的协议。 如果以太网使用的是TCP/IP协议栈,那么Type值要么是0x0800(IPv4),要么是0x0806(ARP),要么是0x…

USP技术提升大语言模型的零样本学习能力

大语言模型&#xff08;LLMs&#xff09;在零样本和少样本学习能力上取得了显著进展&#xff0c;这通常通过上下文学习&#xff08;in-context learning, ICL&#xff09;和提示&#xff08;prompting&#xff09;来实现。然而&#xff0c;零样本性能通常较弱&#xff0c;因为缺…

AndroidStudio的Iguana版的使用

1.AndroidStudio介绍 Android Studio 是用于开发 Android 应用的官方集成开发环境 (IDE)。Android Studio 基于 IntelliJ IDEA 强大的代码编辑器和开发者工具&#xff0c;还提供更多可提高 Android 应用构建效率的功能&#xff0c;例如&#xff1a; 基于 Gradle 的灵活构建系统…

YOLOv5 V7.0 - rknn模型的验证 输出精度(P)、召回率(R)、mAP50、mAP50-95

1.简介 RKNN官方没有提供YOLOv5模型的验证工具&#xff0c;而YOLOv5自带的验证工具只能验证pytorch、ONNX等常见格式的模型性能&#xff0c;无法运行rknn格式。考虑到YOLOv5模型转换为rknn会有一定的精度损失&#xff0c;但是需要具体数值才能进行评估&#xff0c;所以需要一个…

荷香堪筑梦,鸳鸯和月寻。(变相BFS搜索)

本题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 题目&#xff1a; 样例&#xff1a; 输入 3 4 2 .... ***. ..a. 输出 yes 思路&#xff1a; 根据题意&#xff0c;这里 1 s 可以移动多次&#xff0c;我们将每次可以移动避开雪的的位置存储起来&#xff0c;判断当…

线程池

文章目录 普通线程池自定义线程池 普通线程池 //创建线程池&#xff0c;不指定上限 ExecutorService pool1 Executors.newCachedThreadPool(); //创建线程池&#xff0c;指定上限 ExecutorService pool1 Executors.newFixedThreadPool(5); --------------------------------…

【Linux】文件内容相关的命令,补充:管道符

1、查看文件内容 &#xff08;1-1&#xff09;查看文件内容&#xff1a;cat&#xff0c;tac&#xff0c;head&#xff0c;tail 查看文件内容cat 文件名查看文件内容并显示行号cat -n 文件名倒着查看文件内容&#xff08;从最后一行开始&#xff09;tac 文件名查看文件前10行…