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

/*【基本要求】
(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].weight
			if (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( )函数从相应的流文件中读出一个字符,并将其返回给变量ch
		if (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("输入有误,请重新输入");
		}
	}
}



运行结果:

 

 

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

 

 

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

 

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

 

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

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入源码分析kubernetes informer机制(二)Reflector

[阅读指南] 这是该系列第二篇 基于kubernetes 1.27 stage版本 为了方便阅读&#xff0c;后续所有代码均省略了错误处理及与关注逻辑无关的部分。 文章目录 Reflector是什么整体结构工作流程list拉取数据缓存resync操作watch监听操作 总结 Reflector是什么 reflector在informer…

爬虫逆向实战(七)--猿人学第十六题

一、数据接口分析 主页地址&#xff1a;猿人学第十六题 1、抓包 通过抓包可以发现数据接口是api/match/16 2、判断是否有加密参数 请求参数是否加密&#xff1f; 通过查看“载荷”模块可以看出m是加密参数 请求头是否加密&#xff1f; 无响应是否加密&#xff1f; 无cook…

云聊天项目测试

前言 以下将对云聊天项目编写测试用例以及主要功能的自动化测试。 1. 测试用例的编写 2. 自动化测试 以下进行部分自动化测试用例的执行&#xff0c;检验项目功能是否符合预期。 2.1 登录功能测试 测试代码&#xff1a; 输入非法用户名或密码逻辑相似&#xff0c;不重复描…

安防监控视频汇聚平台EasyCVR视频平台调用iframe地址无法播放的问题解决方案

安防监控视频汇聚平台EasyCVR基于云边端一体化架构&#xff0c;具有强大的数据接入、处理及分发能力&#xff0c;可提供视频监控直播、云端录像、视频云存储、视频集中存储、视频存储磁盘阵列、录像检索与回看、智能告警、平台级联、云台控制、语音对讲、AI算法中台智能分析无缝…

冷冻冷藏自动化立体库|HEGERLS四向穿梭车助力打造冷链智能仓储新力量

随着中国仓储物流整体规模和低温产品消费需求的稳步增长&#xff0c;冷链市场应用潜力不断释放。而在实际运行中&#xff0c;由于冷库容量不足、基础设施落后、管理机制欠缺等原因&#xff0c;经常出现“断链”现象&#xff0c;严重威胁到产品质量和消费者安全。 河北沃克金属…

React Native expo项目修改应用程序名称

https://expo.dev/accounts/xutongbao/projects npm install --global eas-cli && \eas init --id e32cf2c0-da5b-4a65-814a-4958d58f0ca7 eas init --id e32cf2c0-da5b-4a65-814a-4958d58f0ca7 app.config.js: export default {name: 学习,slug: learn-gpt,owner: x…

Comparable和Comparator区别

Comparable和Comparator接口都是实现集合中元素的比较、排序的&#xff0c;众所周知&#xff0c;诸如Integer&#xff0c;double等基本数据类型&#xff0c;java可以对他们进行比较&#xff0c;而对于类的比较&#xff0c;需要人工定义比较用到的字段比较逻辑。总体来讲&#x…

【微服务技术二】Feign、Gateway(路由、过滤器、跨域)的初步认知

微服务技术二 五、Feign远程调用Feign替代RestTemplate自定义Feign配置方式一&#xff1a;配置文件方式&#xff1a;方式二&#xff1a;java代码方式 Feign性能优化Feign的最佳实践* 六、Gateway网关搭建网关服务路由断言工厂Route Predicate Factory路由过滤器 GatewayFilter默…

负载均衡下的 WebShell 连接

目录 负载均衡简介负载均衡的分类网络通信分类 负载均衡下的 WebShell 连接场景描述难点介绍解决方法**Plan A** **关掉其中一台机器**&#xff08;作死&#xff09;**Plan B** **执行前先判断要不要执行****Plan C** 在Web 层做一次 HTTP 流量转发 &#xff08;重点&#xff0…

排名前 6 位的数学编程语言

0 说明 任何对数学感兴趣或计划学习数学的人&#xff0c;都应该至少对编程语言有一定的流利程度。您不仅会更有就业能力&#xff0c;还可以更深入地理解和探索数学。那么你应该学习什么语言呢&#xff1f; 1.python 对于任何正在学习数学的人来说&#xff0c;Python都是一门很棒…

vue所有UI库通用)tree-select 下拉多选(设置 maxTagPlaceholder 隐藏 tag 时显示的内容,支持鼠标悬浮展示更多

如果可以实现记得点赞分享&#xff0c;谢谢老铁&#xff5e; 1.需求描述 引用的下拉树形结构支持多选&#xff0c;限制选中tag的个数&#xff0c;且超过制定个数&#xff0c;鼠标悬浮展示更多已选中。 2.先看下效果图 3.实现思路 首先根据API文档&#xff0c;先设置maxTagC…

LVS-DR+keepalived实现高可用负载群集

VRRP 通信原理&#xff1a; VRRP就是虚拟路由冗余协议&#xff0c;它的出现就是为了解决静态路由的单点故障。 VRRP是通过一种竞选的一种协议机制&#xff0c;来将路由交给某台VRRP路由。 VRRP用IP多播的方式&#xff08;多播地址224.0.0.18&#xff09;来实现高可用的通信&…

Redis中的有序集合

前言 本文着重介绍Redis中的有序集合的底层实现中的跳表 有序集合 Sorted Set Redis中的Sorted Set 是一个有序的无重复值的集合&#xff0c;他底层是使用压缩列表和跳表实现的&#xff0c;和Java中的HashMap底层数据结构&#xff08;1.8&#xff09;链表红黑树异曲同工之妙…

记一次mysql8 在linux上安装全过程

参照MYSQL官网官方文档安装 1、mysql官网 mysql官网 2、直接进入文档页 找到安装文档 3、找到自己系统对应的安装文档&#xff0c;选合适的安装方式&#xff0c;我这里使用的是YUM方式 a、开始安装之前需要替换yum仓库 具体步骤如下 b、将下载的文件上传至自己的服务器 如下…

什么是原型(prototype)和原型链(prototype chain)?如何继承一个对象的属性和方法?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 原型&#xff08;Prototype&#xff09;和原型链&#xff08;Prototype Chain&#xff09;⭐ 原型&#xff08;Prototype&#xff09;⭐ 原型链&#xff08;Prototype Chain&#xff09;⭐ 继承属性和方法⭐ 写在最后 ⭐ 专栏简介 前端入…

shell脚本之循环语句

循环语句 循环含义 将某代码段重复运行多次&#xff0c;通常有进入循环的条件和退出循环的条件 for循环语句 一般知道循环次数使用for循环 第一类 格式1&#xff1a; for名称 in 取值次数;do;done; 格式2&#xff1a; for 名称 in {取值列表} do done# 打印20次 for i i…

从 Ansible Galaxy 使用角色

从 Ansible Galaxy 使用角色 根据下列要求&#xff0c;创建一个名为 /home/curtis/ansible/roles.yml 的 playbook &#xff1a; playbook 中包含一个 play&#xff0c; 该 play 在 balancers 主机组中的主机上运行并将使用 balancer 角色。 此角色配置一项服务&#xff0c;以…

十、flume的安装

1.解压 2.改名 3.修改权限 4.编辑环境变量并source export FLUME_HOME/usr/local/flume export PATH$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$HIVE_HOME/bin:$HBASE_HOME/bin:$SQOOP_HOME/bin:$PIG_HOME/bin:$FLUME_HOME/bin 5.配置 6.查看版本 7.启动Hadoo…

LLM提示词工程和提示词工程师Prompting and prompt engineering

你输入模型的文本被称为提示&#xff0c;生成文本的行为被称为推断&#xff0c;输出文本被称为完成。用于提示的文本或可用的内存的全部量被称为上下文窗口。尽管这里的示例显示模型表现良好&#xff0c;但你经常会遇到模型在第一次尝试时无法产生你想要的结果的情况。你可能需…

31.Netty源码之客户端启动流程

highlight: arduino-light 客户端启动主要流程 如果看了服务器端的启动流程&#xff0c;这里简单看下就可以了。 java package io.netty.server; ​ import io.netty.bootstrap.Bootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import …