当前位置: 首页 > news >正文

数据结构应用实例(三)——赫夫曼编码

Content:

      • 一、问题描述
      • 二、算法思想
      • 三、代码实现
      • 四、小结

一、问题描述

  对一篇英文文章,统计各字符(仅限于26个小写字母)出现的次数,并据此进行 Huffman 编码。

二、算法思想

  首先,打开文本文件,统计各个小写英文字母出现的次数;
  然后,统计出现过的字母个数 num;
  如果 num<=1,进行相关信息的显示,不进行 Huffman 编码;
  否则,进行 Huffman 编码:
  准备工作:存储出现过的字母编号及出现次数;
  1、根据出现次数,创建 Huffman 树:
  (1)根据求得的 num 个出现次数 { w 1 , w 2 , ⋯ , w n u m } \lbrace w_1,w_2,\cdots,w_{num} \rbrace {w1,w2,,wnum} 构成 num 棵二叉树的集合 F = { T 1 , T 2 , ⋯ , T n u m } F=\lbrace T_1,T_2,\cdots,T_{num} \rbrace F={T1,T2,,Tnum},其中每棵二叉树 T i T_i Ti 中只有一个带权为 w i w_i wi 的根节点,其左右子树均为空;
  (2)在 F 中选取两棵根节点权值最小的树作为左右子树构造一棵新二叉树,其根节点的权值为两棵子树根节点权值之和;
  (3)从 F 中删除这两棵树,并将新生成的树添加到 F 中;
  (4)重复(2)和(3),直到 F 中只含一棵树。所得到的树就是 Huffman 树;
  2、根据 Huffman 树进行 Huffman 编码
  约定 ‘0’ 表示左分支,‘1’ 表示右分支。从某个叶子节点开始,如果没有父节点,表示编码结束;如果其有父节点,如果为父节点的左孩子,编码尾部添加 ‘0’,如果为右孩子,尾部添加 ‘1’,然后向根节点移动:当前节点变为其父节点,父节点变为父节点的父节点,进行相同操作。
  编码结束之后,对编码进行逆置,得到正序编码;
  3、最后显示出现的字母及其出现的次数和 Huffman 编码;

三、代码实现

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#pragma warning(disable:4996)typedef struct myhuffman//赫夫曼树的节点
{int weight;int parent,lchild,rchild;
}HTnode;typedef struct mylist//存放序号和权重
{int index;int weight;
}LI;int *statis();//统计小写英文字母出现的频次,返回存放频次的数组char **huffmanCoding(int *w, int n);//创建huffman编码,w用于存放叶子节点的权重,n表示叶子节点个数void select(HTnode *HT,int k,int *s1,int *s2);//在HT[1,,,k]中选取parent==0且weight最小的两个节点,返回其序号(*s1),(*s2)int main(void)
{int i,j;int *w,num;int **A;//用于存放频次不为0的字母编号和频次char **HC;//获取小写字母出现次数w=statis();	//统计出现过的字母个数num=0;for (i = 1; i <= 26; i++){if (w[i] != 0)num++;}printf("\n字母出现的次数和Huffman编码如下:\n");if (num == 0)printf("\n没有出现小写英文字母,无需进行Huffman编码\n");else // num>=1{A=(int **)malloc(2*sizeof(int *));A[0]=(int *)malloc((num+1)*sizeof(int));A[1]=(int *)malloc((num+1)*sizeof(int));//向A中存放数据j=1;for (i = 1; i <= 26 && j <= num; i++){if (w[i] != 0){A[0][j]=i;A[1][j]=w[i];j++;}}if (num == 1)printf("只出现了一个字母:%c,频次%d,其Huffman编码为1\n", A[0][1] + 'a' - 1, A[1][1]);else // num>=2{//创建huffman编码HC = huffmanCoding(A[1], num);//显示huffman编码			for (i = 1; i <= num; i++)printf("%c,频次:%2d,编码:%s\n", A[0][i] + 'a' - 1, A[1][i], HC[i]);free(HC);}free(A);}free(w);	return 0;
}int *statis()//统计小写英文字母出现的频次,返回存放频次的数组
{int i;int *w;FILE *fp;char ch,filename[50];//初始化w=(int *)malloc(27*sizeof(int));for (i = 1; i <= 26; i++)w[i]=0;//打开文件printf("请输入文件名:");scanf("%s",filename);fp=fopen(filename,"r");if (!fp){printf("文件不存在!\n");exit(-1);}//统计小写字母出现次数printf("\n文本信息为:\n");while (!feof(fp)){ch=fgetc(fp);printf("%c",ch);if ('a' <= ch && ch <= 'z')w[ch - 'a' + 1]++;}printf("\n");//关闭文件fclose(fp);return w;
}char **huffmanCoding(int *w, int n)//创建huffman编码,w用于存放叶子节点的权重,n表示叶子节点个数
{int i,j,k,l;HTnode *HT,p;int m;int s1,s2;char **HC;char *cd;//一、创建huffman树m=2*n-1;//总的节点个数HT=(HTnode *)malloc((m+1)*sizeof(HTnode));//HT为结构体数组,用于存放huffman树的节点//初始化for (i = 1; i <= n; i++)//叶子节点{p.weight=w[i];p.parent=0;p.lchild=p.rchild=0;HT[i]=p;}for (; i <= m; i++)//非叶子节点{p.weight=0;p.parent=0;p.lchild=p.rchild=0;HT[i]=p;}//合并子树for (i = n + 1; i <= m; i++){select(HT,i-1,&s1,&s2);//在HT[1,,,i-1]中选取parent==0且weight最小的两个节点,并返回其序号HT[s1].parent=i;HT[s2].parent=i;HT[i].weight=HT[s1].weight+HT[s2].weight;HT[i].lchild=s1;HT[i].rchild=s2;}//二、生成huffman编码HC=(char **)malloc((n+1)*sizeof(char *));cd=(char *)malloc(n*sizeof(char));cd[n-1]='\0';//字符串结束标志for (i = 1; i <= n; i++)//对各个叶子节点进行编码{j=n-1;k=i;l=HT[i].parent;while (l != 0){j--;if(HT[l].lchild == k)cd[j]='0';elsecd[j]='1';//更新循环变量k=l;l=HT[l].parent;}//为第i个编码分配空间并赋值HC[i]=(char *)malloc((n-j)*sizeof(char));strcpy(HC[i],&cd[j]);}free(HT);free(cd);return HC;
}void select(HTnode *HT, int k, int *s1, int *s2)//在HT[1,,,k]中选取parent==0且weight最小的两个节点,返回其序号(*s1),(*s2)
{int i,j;int n,lastindex;LI *T,temp;if(k <= 1)return;T=(LI *)malloc((k+1)*sizeof(LI));j=0;for (i = 1; i <= k; i++)//挑选parent==0的点{if (HT[i].parent == 0){j++;T[j].index=i;T[j].weight=HT[i].weight;}}//对T冒泡排序,寻找weight最小的两个节点n=j;//parent==0的节点个数lastindex=n;while (lastindex > n - 2)//至多进行两趟冒泡排序{i=lastindex;lastindex=0;for (j = 1; j < i; j++){if (T[j].weight < T[j + 1].weight)//交换两个数据,小的放在后面{temp=T[j];T[j]=T[j+1];T[j+1]=temp;lastindex=j;}}}//返回节点序号(*s1)=T[n].index;(*s2)=T[n-1].index;free(T);
}

四、小结

1、 由于 Huffman 树中没有出度为1的点,所以可以根据叶子节点的个数 n 0 n_0 n0 事先确定总的节点个数为 2 n 0 − 1 2n_0-1 2n01
2、 结构体变量之间可以直接赋值;
3、 在寻找 parent==0 且 weight 最小的两个节点时,只需进行至多两次的冒泡排序,大大提高了查找效率和算法性能;
4、 进行 Huffman 编码时,由于是从叶子节点开始向前回溯到根节点,所以编码时从后向前进行,这样就避免了逆置编码;
5、 对于特殊情况:出现的英文字母个数小于等于1,则不进行 Huffman 编码;

相关文章:

数据结构应用实例(三)——赫夫曼编码

Content&#xff1a; 一、问题描述二、算法思想三、代码实现四、小结 一、问题描述 对一篇英文文章&#xff0c;统计各字符&#xff08;仅限于26个小写字母&#xff09;出现的次数&#xff0c;并据此进行 Huffman 编码。 二、算法思想 首先&#xff0c;打开文本文件&#xff0…...

关于Spring Cloud Gateway中 Filters的理解

Spring Cloud Gateway中 Filters的理解 Filters Filters拦截器的作用是&#xff0c;对请求进行处理 可以进行流量染色 ⭐增加请求头 例子 spring:cloud:gateway:routes:- id: add_request_header_routeuri: http://localhost:8123predicates:- Path/api/**filters:- AddR…...

【实践】应用访问Redis突然超时怎么处理?

目录标题 问题描述分析过程查看监控数据系统监控指标JVM监控指标Redis监控指标分析应用异常单机异常规律集群异常规律统计超时的key 初步结论验证结论访问Redis链路slowlogRedis单节点info all定位redis节点定位异常keybigkeystcpdump定位大key影响 经验总结 问题描述 某产品线…...

Spring Cloud Alibaba核心组件Nacos/Seata/Sentinel

文章目录 Spring Cloud Alibaba介绍Spring Cloud 微服务体系Spring Cloud Alibaba 定位 注册配置中心--Nacos服务治理架构注册中心原理 Nacos介绍Nacos 的关键特性1.服务注册和发现2.动态配置服务3.实时健康监控4.动态DNS服务5.易于集成&#xff1a; Nacos入门示例服务注册与发…...

Ubuntu搭建FTP服务器

1. 首先&#xff0c;我们需要安装和配置xinetd&#xff0c;安装的具体命令如下&#xff1a; sudo apt-get install xinetd 2. 新建tftp工作目录&#xff0c;并添加读、写、执行权限&#xff08;没有权限后面无法正常访问该文件夹&#xff09;&#xff0c;如下图所示。 3. 安装…...

Redis在单线程下删除大Key会发生什么?怎么删除大Key?

大Key的定义 大Key是指在缓存系统&#xff08;如Redis&#xff09;或分布式存储中&#xff0c;单个键&#xff08;Key&#xff09;对应的数据量非常大&#xff0c;通常存储的是大块数据结构&#xff0c;例如包含大量数据的哈希表、列表、集合或有序集合。这种大Key往往会对系统…...

《Exploit temporal cues in multi-camera 3D object detection》论文泛读

ReadPaperhttps://readpaper.com/pdf-annotate/note?pdfId4666749915775385601eId2491528568128599808 针对单帧数据含有的信息太少的问题&#xff0c;提出了一种新的方法&#xff0c;BEVDet4D&#xff0c;这种方法可以访问时间线索&#xff0c;并且取得了较好的表现&#xff…...

十四、centos7 yum报错:cannot find a valid baseurl for repo:base/7/x86_64的解决方案

&#x1f33b;&#x1f33b;目录&#x1f33b;&#x1f33b; 一、 centos7 yum报错&#xff1a;cannot find a valid baseurl for repo:base/7/x86_64二、分析错误三、解决方案3.1 检查网络连接3.2 检查DNS设置3.3 检查YUM仓库配置3.3.1 使用官方CentOS镜像配置3.3.2 使用阿里云…...

qt使用对数坐标的例子,qchart用QLogValueAxis坐标不出图解决

硬件&#xff1a;ThinkPad T15 系统&#xff1a;win10 专业版 qt版本&#xff1a;Qt 5.14.1 &#xff0c; QtCreator 4.11.1 软件界面放了一个QPushButton&#xff0c;一个QVBoxLayout&#xff0c;如下&#xff1a; 主要代码如下&#xff0c;我添加了两条曲线&#xff0c;…...

Python 爬虫入门 - 爬虫 requests 请求

在当今互联网时代,数据的获取变得尤为重要,而网络爬虫作为自动化获取数据的一种方式,受到了越来越多编程爱好者和数据分析人员的青睐。Python 语言以其简洁的语法和丰富的库,成为了实现网络爬虫的首选工具。其中,requests库是一个非常流行且强大的工具,用于发送 HTTP 请求…...

flink中startNewChain() 的详解

在 Apache Flink 中&#xff0c;startNewChain() 是一个与算子链&#xff08;operator chaining&#xff09;相关的方法。与 disableChaining() 类似&#xff0c;它允许开发者控制算子链的创建方式&#xff0c;但 startNewChain() 的作用是从当前算子开始创建一个新的算子链&am…...

uniapp 苹果安全域适配

一、使用原生占位&#xff08;仅App端支持&#xff09; //在manifest.json 文件中 app-plus 中配置 "safearea": { "background": "#FFFFFF", "bottom": { "offset": "auto" } } 二、不使用原生占位 //&…...

linux使用命令行编译qt.cpp

步骤&#xff1a; mkdir qttestcd qttestvim hello.cpp #include <QApplication> #include <QDialog> #include <QLabel> int main(int argc,char* argv[]) {QApplication a(argc,argv);QLabel label("aaa");label.resize(100,100);label.show()…...

Ubuntu 22.04 LTS 上安装 Docker

单台机器安装docker环境&#xff0c;是为了后面安装open-webui&#xff0c;环境安装比较简单&#xff0c;没有难点&#xff0c;但一定要按步骤走&#xff0c;否则还是会遇到一些问题的。 第 1 步&#xff1a;更新软件包并安装必要软件 运行以下命令&#xff0c;更新软件包索引…...

2024秋季云曦开学考

web ezezssrf 打开环境&#xff0c;代码审计 看起来有点多&#xff0c;要绕过五层 第一层&#xff1a;存在弱比较&#xff0c;使用数组或0e绕过 yunxi[]1&wlgf[]2 yunxis878926199a&wlgfs155964671a 第二层&#xff1a;存在强比较&#xff0c;此处使用string限制…...

基于STM32与Qt的自动平衡机器人:从控制到人机交互的的详细设计流程

一、项目概述 目标和用途 本项目旨在开发一款基于 STM32 控制的自动平衡机器人&#xff0c;结合步进电机和陀螺仪传感器&#xff0c;实现对平衡机器人的精确控制。该机器人可以用于教育、科研、娱乐等多个领域&#xff0c;帮助用户了解自动控制、机器人运动学等相关知识。 技…...

C#使用ZipFile的方法CreateFromDirectory

由于现在数据越来越大,虽然磁盘的大小也在增加,但是数据增加的速度是远超过磁盘的增加速度。 因为数据是一种思想的表现,特别是ChatGPT的AI出现,导致很多数据无限地使用机器化地产生,所以数据压缩还是很常有的事情,毕竟压缩之后可以减少磁盘空间的占用。 在C#里有一个专…...

Redis 哨兵模式的选举算法是什么?

Redis 哨兵模式中的选举算法主要用于在主节点出现故障时,从多个 Sentinel 节点中选出一个领导者(Leader)来执行故障转移操作。 Redis 哨兵的选举算法基于 Raft 算法的简化版本,但不完全等同于标准的 Raft 算法。以下是其主要过程: 一、发现主节点故障 当一个 Sentinel …...

Linux shell编程学习笔记80:gzip命令——让文件瘦身

0 引言 在 Linux shell编程学习笔记76&#xff1a;tar命令——快照 & 备份&#xff08;上&#xff09;-CSDN博客 Linux shell编程学习笔记77&#xff1a;tar命令——快照 & 备份&#xff08;下&#xff09;_linux 系统快照-CSDN博客 Linux shell编程学习笔记78&am…...

【字幕】恋上数据结构与算法之01为什么要学习数据结构与算法

视频地址&#xff1a;请查看01为什么要学习数据结构与算法_哔哩哔哩_bilibili 同志们好&#xff0c;我是小码哥的mj李明杰。非常欢迎大家来学习链上数据结构与算法&#xff0c;从今天开始呢就由我来带大家一起来学习和掌握这个数据结构与算法啊。在正式学习之前我们先来看一下…...

120页ppt丨集团公司战略规划内容、方法、步骤及战略规划案例研究

响应会员需求&#xff0c;晓零分享一份经典资料《120页ppt集团公司战略规划内容、方法、步骤及战略规划案例研究》&#xff0c;欢迎进入星球下载学习。 以下是对企业战略规划三个阶段八个步骤的详细解析&#xff1a; 一、阶段一&#xff1a;内外分析 项目启动和前期准备&…...

滚雪球学SpringCloud[2.3]:服务发现与负载均衡详解

全文目录&#xff1a; 前言1. Ribbon的使用与配置1.1 Ribbon 概述Ribbon 的核心功能&#xff1a; 1.2 Ribbon 的基本使用1.2.1 引入 Ribbon 依赖1.2.2 配置 RestTemplate 与 Ribbon1.2.3 示例&#xff1a;通过 Ribbon 调用服务 1.3 Ribbon 的配置选项 2. Ribbon的负载均衡策略2…...

商务英语口语之聚会宴饮常用口语柯桥培训到蓝天广场

吃饭一定要掌握的英语口语 邀请他人共进餐&#xff1a; Would you like to join me for dinner? 你愿意和我一起吃饭吗&#xff1f; Lets grab a bite to eat together. 我们一起去吃点东西吧。 How about having lunch with me? 和我一起吃午饭怎么样&#xff1f; 询问…...

【C#】VS插件

翻译 目前推荐较多的 可以单词发言&#xff0c;目前还在开发阶段 TranslateIntoChinese - Visual Studio Marketplace 下载量最高的(推荐) Visual-Studio-Translator - Visual Studio Marketplace 支持翻译的版本较多&#xff0c;在 Visual Studio 代码编辑器中通过 Googl…...

嵌入式C语言自我修养:C语言的面向对象编程思想

⭐关联知识点&#xff1a;C和C的区别 代码复用与分层思想 什么是代码复用呢&#xff1f; &#xff08;1&#xff09;函数级代码复用&#xff1a;定义一个函数实现某个功能&#xff0c;所有的程序都可以调用这个函数&#xff0c;不用自己再单独实现一遍&#xff0c;函数级的代…...

行车记录仪格式化了怎么恢复?专业恢复方法分享

行车记录仪作为现代驾驶的必备设备&#xff0c;它忠实记录着行车过程中的点点滴滴&#xff0c;是保障行车安全、处理交通事故的重要依据。然而&#xff0c;有时由于操作失误或其他原因&#xff0c;我们可能会不小心将行车记录仪进行格式化&#xff0c;导致宝贵的录像数据丢失。…...

C++中extern ”c“的理解

c中extern “C“的作用及理解_extern "c-CSDN博客...

红黑树的删除

文章目录 前言一.删除的节点左子树右子树都有二.删除的节点只有左/右子树删除调整操作 三.删除的节点没有孩子1.删除的节点为红色2.删除的节点为黑色1).兄弟节点为黑色(1).兄弟节点至少有一个红色的孩子节点LL型RR型RL型LR型 (2).兄弟节点没有孩子或所有孩子为黑色 2).兄弟节点…...

Vue3+setup实现父子组件单表增删改查写法模板

父组件写法 <el-card><!-- el-card 头部插槽 显示列表名和新增按钮 --><template #header><div class"table-header-container"><i class"fas fa-th" />角色列表&#xff08;100&#xff09;<span style"flex-grow…...

jmeter 录制APP脚本

一、手机 1、修改网络 代理选择手动→填写服务器主机名&#xff08;电脑IP&#xff0c;如&#xff1a;192.1xx.x.xx&#xff09;→服务器端口&#xff08;任意未被占用端口&#xff0c;如&#xff1a;8888&#xff09; 2、安装证书 手机浏览器访问服务器主机名:服务器端口&a…...