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

数据结构作业——哈夫曼树

/*【基本要求】
(1) 从文件中读出一篇英文文章,包含字母和空格等字符。
(2) 统计各个字符出现的频度。
(3) 根据出现的频度,为每个出现的字符建立一个哈夫曼编码,并输出。
(4)  输入一个字符串,为其编码并输出。
(5) 输入一串编码,为其译码并输出*//*【演示结果】
(1)显示英文文章及各字符出现的频率。
(2)显示每个字符的哈夫曼编码。
(3)文件读入一文本,显示对其编码结果,并存盘
(4)文件读入一组编码,显示对其译码结果,并存盘*/#include<stdio.h>
using namespace std;#define N 128//最多128个字符种类//数据存储结构
typedef struct{char data;//数据int weight;//数据权重int lchild,rchild,parent;//左右结点及双亲
}HumfNode;//词频统计存储结构
typedef struct{char data;int freq;
}Datafreq;//编码存储结构
typedef struct{int bits[128];存放编码0、1的数组int start;
}HCode;

代码:

#include<stdio.h>
#include<string.h>
#include<conio.h>
#include<stdlib.h>
#include<fstream>
#include<iostream>
using namespace std;
#define N 128                                            //最大叶子结点数typedef struct
{char data;                                          //编码对应的字符int weight;                                         //结点的权值int lchild, rchild, parent;
}HumfNode;typedef struct
{char data;int freq;
}Datafreq;typedef struct
{int bits[128];                                        //存放哈夫曼编码的字符数组int start;                                           //编码的起始位置
}HCode;void FreqNode(char* st, Datafreq str[])                   //统计单词和空格与其频率
{int i, j, k, num[128];char* p = st;for (i = 0; i < 128; i++){str[i].freq = 0;}//初始化频度结点的频度for (i = 0; i < 128; i++)num[i] = 0;//printf("英文文章如下:");while (*p != NULL){num[int(*p)]++;p++;}j = 0;for (i = 0; i < 128; i++){str[i].data = char(i);str[i].freq = num[i];//统计每个结点的权重和内容}printf("\n");printf("频度如下(ascll码由小到大排列):");for (i = 0; i < 128; i++){if (str[i].freq != '\0'){cout << str[i].data << str[i].freq << " ";}}printf("\n");}//功能实现的是统计文档中的各个字符的出现频率
//将整个ascll码表全部存储,并将其频度(权重)和内容放入哈夫曼结点中
void CreatHufmTree(HumfNode tree[], Datafreq str[], int n)                    //建立哈夫曼树                 
{int m1, m2, i, l, r, k;Datafreq* p = str;for (i = 0; i < 2 * n - 1; i++){tree[i].lchild = tree[i].rchild = tree[i].parent = -1;tree[i].weight = 0;}for (i = 0; i < n; i++){tree[i].data = p[i].data;tree[i].weight = p[i].freq;}for (i = n; i < 2 * n - 1; i++){m1 = m2 = 32767;l = r = -1;for (k = 0; k < i; k++){if (tree[k].parent == -1 && tree[k].weight <= m1){m2 = m1;r = l;m1 = tree[k].weight;l = k;}else if (tree[k].parent == -1 && tree[k].weight <= m2){m2 = tree[k].weight;r = k;}else{}}tree[i].weight = tree[l].weight + tree[r].weight;tree[i].lchild = l;tree[i].rchild = r;tree[l].parent = i;tree[r].parent = i;if (tree[i].weight == tree[l].weight){tree[i].data = tree[l].data;tree[i].weight = tree[l].weight;tree[i].lchild = tree[i].rchild = -1;}else if (tree[i].weight == tree[r].weight){tree[i].data = tree[r].data;tree[i].weight = tree[r].weight;tree[i].lchild = tree[i].rchild = -1;}//下标为i的新结点成为权值最小的两个结点双亲//新结点的权值为两个结点权值之和//权值最小的结点是新结点的左孩子//权值次最小的结点为右孩子}}//建立哈夫曼树void HufmCode(HumfNode tree[], HCode hcd[], int n)                    //哈夫曼编码的生成
{int i, f, c, k;HCode cd;                                          //用于临时存放编码串for (i = 0; i < 128; i++){for (int r = 0; r < N; r++){cd.bits[r] = 2;}cd.start = n - 1;c = i;                                                    //从叶子结点开始往上回溯f = tree[i].parent;//找到它的双亲结点while (f != -1)                                             //回溯到根结点{//&& tree[f].weight != tree[c].weightif (tree[f].lchild == c && tree[tree[f].rchild].weight != tree[f].weight && tree[tree[f].lchild].weight != tree[f].weight){cd.bits[cd.start] = 0;cd.start--;c = f;f = tree[c].parent;}else if (tree[f].rchild == c && tree[tree[f].rchild].weight != tree[f].weight && tree[tree[f].lchild].weight != tree[f].weight){cd.bits[cd.start] = 1;cd.start--;c = f;f = tree[c].parent;}else{tree[f].data = tree[tree[f].rchild].data;tree[f].weight = tree[tree[f].rchild].weight;tree[f].lchild = tree[f].rchild = -1;c = f;f = tree[c].parent;}}//cd.start++;hcd[i] = cd;}printf("输出哈夫曼编码:\n");for (i = 0; i < n; i++){if (tree[i].weight != 0){printf("%c\n", tree[i].data);for (k = hcd[i].start + 1; k < n; k++){printf("%d", hcd[i].bits[k]);}printf("\n");}}
}string TsCode( char a[], HumfNode tree[], int n)                          //哈夫曼树的译码
{char* p = a;int i = 0;int k = 0;i = 2 * n - 2;string tsresult;//将树根结点的下标赋i,从根结点出发向下搜索a = p;//unsigned long len = strlen(a);printf("译码结果如下:");while (*a != '2'&&*a!='\0'){if (*a == '0'){//printf("%d\n", tree[i].weight);i = tree[i].lchild;if ((tree[i].lchild == -1) && (tree[i].rchild == -1)){//printf("%d\n", tree[i].weight);printf("%c", tree[i].data);tsresult+=tree[i].data;i = 2 * n - 2;k++;}a++;}else if (*a == '1'){//printf("%d\n", tree[i].weight);i = tree[i].rchild;if ((tree[i].lchild == -1) && (tree[i].rchild == -1)){//printf("%d\n", tree[i].weight);printf("%c", tree[i].data);tsresult += tree[i].data;i = 2 * n - 2;k++;}a++;}}return tsresult;
}void outputfiles(string file,string a)
{ofstream fout(file);fout << a;fout.close();}void outputfile(string file, HCode hcd[], HumfNode tree[], int n)
{int i, k;ofstream fout(file);if (!fout){cout << "文件不能打开" << endl;}else{// 输出到磁盘文件for (i = 0; i < n; i++){if (tree[i].data != '\0' && tree[i].weight != 0){fout << tree[i].data << ":";for (k = hcd[i].start + 1; k < n; k++)if (hcd[i].bits[k] != 2){fout << hcd[i].bits[k];}fout << endl;printf("\n");}}//关闭文件输出流fout.close();}
}char* openfile(string file, char* st)                            //打开并显示文件
{char ch;int i = 0;ifstream infile;infile.open(file.data());   //将文件流对象与文件连接起来 while (!infile.eof()){infile.get(ch); //get( )函数从相应的流文件中读出一个字符,并将其返回给变量chif (infile.fail()){break;}st[i] = ch;//cout << ch;i++;}infile.close();       //关闭文件return st;
}void Getcode(char* bit, HumfNode tree[], HCode hcd[], int n)
{char* p = bit;int i = 0, k;while (*(bit + i) != '\0'){for (k = 0; k < n; k++){if (tree[k].data == *(bit + i)){for (int r = hcd[k].start; r < n; r++)printf("%d", hcd[k].bits[r]);}}i++;}//while (*p != '\0')//{//	int i = 1, k;//	while (i <= n)//	{//		if (tree[i].data == *p)//		{//			//	printf("输出哈夫曼编码:\n");//			//	printf("%c",tree[i].data);//			for (k = hcd[i].start; k <= n; k++)//				printf("%c", hcd[i].bits[k]);//			//	printf("\n");//		}//		i++;//		//	else//		//		i++;//	}//	p++;//}
}void main()
{int i, j, k, t = 0, m, b;char x;int n = 128;Datafreq str[128], stt[128], sft[128], num[128];char st[1000], bm[200], sd[50], sf[50], sm[50];HumfNode tree[2 * N - 1], st_tree[2 * N - 1], sf_tree[2 * N - 1];                                 //用于存放树中所有结点HCode hcd[N], st_hcd[N], hst[N];   //用于存放字符的哈夫曼编码char* ss, * yima;string tscode;while (1){printf("******************************************************************************\n");printf("******************************************************************************\n");printf("**   1.从文件中读出一篇英文文章,包含字母和空格等字符。                     **\n");printf("**   2.统计各个字符出现的频度,为每个出现的字符建立一个哈夫曼编码,并输出。 **\n");printf("**   3.输入一个字符串,为其编码并输出。                                     **\n");printf("**   4.输入一串编码,为其译码并输出。                                       **\n");printf("**   5.退出                                                                 **\n");printf("******************************************************************************\n");printf("******************************************************************************\n");scanf_s("%d", &x);switch (int(x)){case 1:for (int y = 0; y < 1000; y++){st[y] = '\0';}ss = openfile("D:\\mathess\\eee.txt", st);printf("英文文章如下:");while (*ss != '\0'){printf("%c", *ss);ss++;}printf("\n");break;case 2:  FreqNode(st, str);CreatHufmTree(tree, str, n);//cout << tree[65].data;HufmCode(tree, hcd, n);outputfile("D:\\mathess\\eeecode.txt", hcd, tree, n);break;case 3: printf("请输入一个字符串:");scanf_s("%s", &sd, 50);FreqNode(sd, stt);CreatHufmTree(st_tree, stt, n);HufmCode(st_tree, st_hcd, n);//Getcode(sd, tree, hcd, n);break;case 4:	printf("请输入一个字符串(为后面的译码内容提供编码参考):");scanf_s("%s", &sf, 50);FreqNode(sf, sft);CreatHufmTree(sf_tree, sft, n);HufmCode(sf_tree, hst, n);for (int i = 0; i < 200; i++){bm[i] = '2';}yima = openfile("D:\\mathess\\xuyaoyima.txt", bm);i = 0;printf("文档的一串编码为:");while (*yima != '\0'){if (*yima == '0' || *yima == '1'){printf("%c", *yima);yima++;}else{break;}}printf("\n");//scanf_s("%s", bm, 200);//printf("译码后的结果:");tscode=TsCode( bm, sf_tree, n);//printf("%s", tscode);//printf("%c", * Tscode);outputfiles("D:\\mathess\\tscode.txt", tscode);printf("\n");break;case 5: exit(0);//	default: printf("输入有误,请重新输入");}}
}

运行结果:

 

 

从文件读取英文文章,并显示读取后的文章内容

 

 

将其统计频率进行输出,并将编码结果存盘

 

输入需要编码的字符串,并将译码结果输出

 

输入需要译码的编码,进行译码,并将译码结果输出,存盘,经过判断结果正确。

 

 

相关文章:

数据结构作业——哈夫曼树

/*【基本要求】 &#xff08;1&#xff09; 从文件中读出一篇英文文章&#xff0c;包含字母和空格等字符。 &#xff08;2&#xff09; 统计各个字符出现的频度。 &#xff08;3&#xff09; 根据出现的频度&#xff0c;为每个出现的字符建立一个哈夫曼编码&#xff0c;并输出。…...

Python XML处理中级篇:深入探索lxml库

lxml库是Python中处理XML和HTML文档的强大库&#xff0c;提供了丰富的API以进行各种操作。在初级篇中&#xff0c;我们介绍了如何使用lxml库解析、访问和修改XML文档。在这篇中级篇中&#xff0c;我们将更深入地探讨如何使用lxml库&#xff0c;包括如何创建XML文档&#xff0c;…...

岩棉革新——洛科威推出NGF新一代岩棉产品

作为全球领先的岩棉制品生产商&#xff0c;洛科威公司基于在岩棉性能革新领域八十多年的深入研究和生产工艺的不断优化&#xff0c;在中国市场正式推出NGF新一代岩棉制品&#xff0c;并在上海国际绿色建筑建材博览会和2023国际绿色低碳技术展上正式发布。 洛科威NGF产品作为革…...

关于 docker 基础题目

1.安装docker服务&#xff0c;配置镜像加速器 http://t.csdn.cn/E3zQ8 2.下载系统镜像&#xff08;Ubuntu、 centos&#xff09; 执行该命令后&#xff0c;Docker会自动从Docker Hub镜像库中下载Ubuntu镜像&#xff0c;并将其保存到本地计算机上: [rootmaster ~]# docker pull …...

Skywalking全链路追踪【学习笔记】

Skywalking全链路追踪的服务搭建&#xff0c;使用docker进行安装。 搭建服务 搭建【ES】 # 拉取 docker pull docker.elastic.co/elasticsearch/elasticsearch:7.17.10 # 启动 docker run -p 127.0.0.1:9200:9200 -p 127.0.0.1:9300:9300 -e "discovery.typesingle-nod…...

Sphinx——Python生成API文档

1、简介 Sphinx是Python文档生成器&#xff0c;它基于reStructuredText标记语言&#xff0c;可自动根据项目生成HTML&#xff0c;PDF等格式的文档&#xff0c;无数著名项目的文档均用Sphinx生成&#xff0c;如机器学习库scikit-learn、交互式神器Jupyter Notebook sphinx是一…...

倒计时动效

1. 效果 2. html <div class"count"><span>3</span><span>2</span><span>1</span> </div>3. css body {width: 100vw;height: 100vh;overflow: hidden;display: flex;justify-content: center;align-items: cente…...

安卓主板定制_电磁屏/电容屏安卓平板基于MTK联发科方案定制

定制化行业平板 在各行各业中的地位越来越重要&#xff0c;甚至在行业转型和发展中发挥着不可替代的作用。随着工业化社会的快速发展&#xff0c;工业生产对智控设备要求越来越高&#xff0c;运用的范畴也越来越普遍广泛&#xff0c;工业级平板就是其中一种应用广泛的设备。 新…...

Unity 之 ScreenPointToRay() (将点转换成射线的方法)

文章目录 ScreenPointToRay() ScreenPointToRay() ScreenPointToRay() 是Unity中Camera类的一个方法&#xff0c;用于将屏幕上的一个点转换为一条射线。这条射线的起点是摄像机在屏幕上对应的点&#xff0c;方向是从摄像机出发指向那个点。这在进行射线命中检测时非常有用&…...

C++ 线程池

目录 一、线程池实现原理 二、定义线程池的结构 三、创建线程池实例 四、添加工作的线程的任务函数 五、管理者线程的任务函数 六、往线程池中添加任务 七、获取线程池工作的线程数量与活着的线程数量 八、线程池的销毁 一、线程池实现原理 线程池的组成主要分为3个部…...

测试框架pytest教程(6)钩子函数hook开发pytest插件

pytest hook 函数也叫钩子函数&#xff0c;pytest 提供了大量的钩子函数&#xff0c;可以在用例的不同生命周期自动调用。 比如&#xff0c;在测试用例收集阶段&#xff0c;可利用 hook 函数修改测试用例名称的编码。 pytest的hook是基于Python的插件系统实现的&#xff0c;使…...

【Rust】Rust学习 第十七章Rust 的面向对象特性

面向对象编程&#xff08;Object-Oriented Programming&#xff0c;OOP&#xff09;是一种模式化编程方式。对象&#xff08;Object&#xff09;来源于 20 世纪 60 年代的 Simula 编程语言。这些对象影响了 Alan Kay 的编程架构中对象之间的消息传递。他在 1967 年创造了 面向对…...

Redis系列(四):哨兵机制详解

首发博客地址 https://blog.zysicyj.top/ 前面我们说过&#xff0c;redis采用了读写分离的方式实现高可靠。后面我们说了&#xff0c;为了防止主节点压力过大&#xff0c;优化成了主-从-从模式 思考一个问题&#xff0c;主节点此时挂了怎么办 这里主从模式下涉及到的几个问题&a…...

一个滚动框高度动态计算解决方案

需求描述&#xff0c;一个嵌套了很多层div或者其他标签的内容框&#xff0c;而它的外层没有设置高度&#xff0c;或者使用百分比&#xff0c;而本容器需要设置高度来实现滚动&#xff0c;要么写死px高度&#xff0c;但是不能自适应&#xff0c;此时需要一个直系父容器&#xff…...

Android瀑布流

以下是一个简单的示例代码&#xff0c;演示如何在Android Studio中解析指定网页的图片URL&#xff0c;并展示在错乱瀑布流布局中&#xff1a; 1. 添加网络权限&#xff1a;在项目的AndroidManifest.xml文件中添加以下权限&#xff1a; <uses-permission android:name"…...

Ubuntu搭建CT_ICP里程计的环境暨CT-ICP部署

CT-ICP部署以及运行复现过程 0.下载资源&#xff0c;并按照github原网址的过程进行。1.查看所需要的各个部分的版本。2.安装clang编译器3.进行超级构建3.1标准进行3.2构建过程中遇到的问题 4.构建并安装CT-ICP库4.1标准进行4.2遇到的问题及解决办法 5.构建 CT-ICP 的 ROS 包装5…...

微信小程序全局事件订阅eventBus

微信小程序全局事件订阅 在Vue开发中&#xff0c;我们可能用过eventBus来解决全局范围内的事件订阅及触发逻辑&#xff0c;在微信小程序的开发中我们可能也也会遇到同样的需求&#xff0c;那么我们尝试下在小程序&#xff08;原生小程序开发&#xff09;中实现类似eventBus的事…...

华为云cce发布若依前后分离版:2.nginx镜像操作

下载nginx docker的官方镜像。 docker资源很难找,我在我的空间上传了一个,需要的话可以下载: https://download.csdn.net/download/axe6404/88225311 下载后,请用以下方法安装 2.1 导入docker 官方nginx镜像。 将镜像包nginx docker镜像包nginx-dockerimage.tar放…...

TCP协议报文结构

TCP是什么 TCP&#xff08;传输控制协议&#xff09;是一种面向连接的、可靠的、全双工的传输协议。它使用头部&#xff08;Header&#xff09;和数据&#xff08;Data&#xff09;来组织数据包&#xff0c;确保数据的可靠传输和按序传递。 TCP协议报文结构 下面详细阐述TCP…...

Day14-2-NodeJS后端开发流程

Day14-NodeJS后端工程化流程 一 apifox工具 apifox是目前最好的接口调试工具 1 环境搭建 安装登录创建项目接口里面创建对应文件夹在指定的文件夹里面创建接口2 GET请求 1 apifox发送GET请求 2 后端接收GET请求 router.get("/getUserinfo"...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录

ASP.NET Core 是一个跨平台的开源框架&#xff0c;用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录&#xff0c;以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

管理学院权限管理系统开发总结

文章目录 &#x1f393; 管理学院权限管理系统开发总结 - 现代化Web应用实践之路&#x1f4dd; 项目概述&#x1f3d7;️ 技术架构设计后端技术栈前端技术栈 &#x1f4a1; 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 &#x1f5c4;️ 数据库设…...

#Uniapp篇:chrome调试unapp适配

chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器&#xff1a;Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...