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

2024-05-07 23:36

本文主要是介绍【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;
}

这篇关于【GDPU】数据结构实验十 哈夫曼编码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/968710

相关文章

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &

《数据结构(C语言版)第二版》第八章-排序(8.3-交换排序、8.4-选择排序)

8.3 交换排序 8.3.1 冒泡排序 【算法特点】 (1) 稳定排序。 (2) 可用于链式存储结构。 (3) 移动记录次数较多,算法平均时间性能比直接插入排序差。当初始记录无序,n较大时, 此算法不宜采用。 #include <stdio.h>#include <stdlib.h>#define MAXSIZE 26typedef int KeyType;typedef char In

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

STM32(十一):ADC数模转换器实验

AD单通道: 1.RCC开启GPIO和ADC时钟。配置ADCCLK分频器。 2.配置GPIO,把GPIO配置成模拟输入的模式。 3.配置多路开关,把左面通道接入到右面规则组列表里。 4.配置ADC转换器, 包括AD转换器和AD数据寄存器。单次转换,连续转换;扫描、非扫描;有几个通道,触发源是什么,数据对齐是左对齐还是右对齐。 5.ADC_CMD 开启ADC。 void RCC_AD

form表单提交编码的问题

浏览器在form提交后,会生成一个HTTP的头部信息"content-type",标准规定其形式为Content-type: application/x-www-form-urlencoded; charset=UTF-8        那么我们如果需要修改编码,不使用默认的,那么可以如下这样操作修改编码,来满足需求: hmtl代码:   <meta http-equiv="Conte

HNU-2023电路与电子学-实验3

写在前面: 一、实验目的 1.了解简易模型机的内部结构和工作原理。 2.分析模型机的功能,设计 8 重 3-1 多路复用器。 3.分析模型机的功能,设计 8 重 2-1 多路复用器。 4.分析模型机的工作原理,设计模型机控制信号产生逻辑。 二、实验内容 1.用 VERILOG 语言设计模型机的 8 重 3-1 多路复用器; 2.用 VERILOG 语言设计模型机的 8 重 2-1 多

【408数据结构】散列 (哈希)知识点集合复习考点题目

苏泽  “弃工从研”的路上很孤独,于是我记下了些许笔记相伴,希望能够帮助到大家    知识点 1. 散列查找 散列查找是一种高效的查找方法,它通过散列函数将关键字映射到数组的一个位置,从而实现快速查找。这种方法的时间复杂度平均为(

浙大数据结构:树的定义与操作

四种遍历 #include<iostream>#include<queue>using namespace std;typedef struct treenode *BinTree;typedef BinTree position;typedef int ElementType;struct treenode{ElementType data;BinTree left;BinTre