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

news2024/11/15 19:26:58
/*【基本要求】
(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("输入有误,请重新输入");
		}
	}
}



运行结果:

 

 

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

 

 

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

 

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

 

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

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Open-Cascade 编译全过程-以及注意事项

1.从Github上下载 该源码库; https://github.com/Open-Cascade-SAS/OCCT 2.再从下面网站,下载需要的地方库文件: 从这个地址下载需要的文件&#xff1b; 3rd party Components | Open CASCADE Technology 3.使用cmak gui进行构建编译; 关键地方以及坑所在得点: 如果其编…

打破壁垒,实现高效的跨部门协作与沟通

在如今复杂多变的商业环境下&#xff0c;企业间需要跨越多个部门的壁垒进行协作及沟通以完成企业目标。尽管如此&#xff0c;许多企业仍然面临协作过程中出现不必要的误解、重复、延迟和错失机会等问题。为此&#xff0c;现代技术提供了一些解决方案&#xff0c;其中最为成功的…

【Terraform学习】使用 Terraform 创建Amazon VPC(Terraform-AWS最佳实战学习)

使用 Terraform 创建Amazon VPC 实验步骤 前提条件 安装 Terraform&#xff1a; 地址 下载仓库代码模版 本实验代码位于 task_vpc 文件夹中。 变量文件 variables.tf 在上面的代码中&#xff0c;您将声明&#xff0c;aws_access_key&#xff0c;aws_secret_key和 区域变量…

视频云存储/安防监控EasyCVR视频汇聚平台如何通过角色权限自行分配功能模块?

视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同&#xff0c;支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。音视频流媒体视频平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;具体可实现视频监控直播、视频轮播、视频录像、…

永久设置pip指定国内镜像源(windows内)

1.首先列出国内四个镜像源网站&#xff1a; 一、清华源 https://pypi.tuna.tsinghua.edu.cn/simple/ 二、阿里源 https://mirrors.aliyun.com/pypi/simple 三、中科大源 https://pypi.mirrors.ustc.edu.cn/simple/ 四、豆瓣源 http://pypi.douban.com/simple/ 2.一般下载所需要…

什么是SaaS、PaaS、aPaaS、iPaaS、IaaS,一文讲透

在数字化的带动下&#xff0c;各行业对云服务的需求进入快速增长期。 SaaS、PaaS、aPaaS、iPaaS、IaaS…… 这些词经常出现&#xff0c;那么他们分别是什么意思&#xff1f;又有什么区别&#xff1f;小帆带大家一起来看看~ SaaS SaaS&#xff0c;Software as a Service&…

数字乡镇综合解决方案[59页PPT]

导读&#xff1a;原文《数字乡镇综合解决方案[59页PPT]》&#xff08;获取来源见文尾&#xff09;&#xff0c;本文精选其中精华及架构部分&#xff0c;逻辑清晰、内容完整&#xff0c;为快速形成售前方案提供参考。 喜欢文章&#xff0c;您可以关注评论转发本文&#xff0c;了…

医疗设备管理软件哪家好?医院设备全生命周期管理要怎么做?

随着医学技术的不断进步&#xff0c;医疗设备变得越来越先进&#xff0c;越来越复杂。因此&#xff0c;医疗设备的管理也变得越来越重要。传统的医疗设备管理方式存在很多问题&#xff0c;比如设备数据难统计、报修方式难统一、巡检维保难规范等。为了解决这些问题&#xff0c;…

无畏限制:项目管理中的狠人哲学

引言 在项目管理的领域中&#xff0c;我们经常面临各种限制条件&#xff0c;从时间、资源到预算。但是&#xff0c;真正的“狠人”不会被这些困难所困扰。他们坚信一个简单的哲学&#xff1a;不论遇到什么问题&#xff0c;都要直面它&#xff0c;攻克它。这种直接、简单、无畏…

【二叉树构建与遍历2】后序遍历+中序遍历构建一个二叉树并输出先序遍历 C++实现

思路&#xff1a; 先来一个例子&#xff1a; 后序遍历序列为&#xff1a;XEDGAF 中序遍历序列为&#xff1a;XDEFAG 要根据后序序列和中序序列确定这个二叉树&#xff0c;通用的步骤为&#xff1a; 1.根据后序序列的最后一位确定这棵树的根&#xff1b; 2.在中序序列中找…

电脑上安装,多版本node

手上有一个vue3的项目&#xff0c;sass配置如下图所示&#xff1a; 安装了Python3.10和node 16.14.0&#xff0c;项目能正常install 跟run。 因工作需要&#xff0c;收上有一个vue2的项目&#xff0c;sass配置如下图所示&#xff1a; 执行npm intsall 的时候一直报Python2找不…

无论是小说、公文还是新闻稿,爱校对都是你的最佳选择

在这个数字化的时代&#xff0c;写作已经渗透到我们生活的方方面面。从小说家到政府官员&#xff0c;再到新闻记者&#xff0c;每个人都需要确保他们的文本内容无瑕疵、逻辑清晰。这就是“爱校对”进入舞台的地方。它不仅仅是一个校对工具&#xff0c;更是每个写作者都不可或缺…

Day13-面向对象编程

Day13-面向对象编程 一 回顾 变量,数组,对象都是容器,都可以用来存储数据 let n = 10 let arr = [3,5,7] let stu = {name:"张恒",age:18,sex:"女"}二 面向对象思想 面向过程:将开发的步骤按照顺序一步一步往下执行,直到程序结束 面向对象:将项目中…

springboot+docker实现微服务的小例子

【任务】&#xff1a; 创建一个服务A&#xff1a;service_hello 创建一个服务B&#xff1a;service_name service_name负责提供一个api接口返回一个name字符串。 service_hello负责从这个接口获取name字符串&#xff0c;然后进行一个字符串拼接&#xff0c;在后面加一个hello&…

冠达管理:8月新股赚嗨了!创业板年内第二高价股来了,本周3股齐发

创业板年内第二高价股来了。 本周&#xff08;8月21日到8月25日&#xff09;总共有3只新股申购。其间&#xff0c;创业板新股儒竞科技定价99.57元/股&#xff0c;是年内创业板第二高价股&#xff0c;将于周一申购&#xff0c;中一签需缴款4.98万元。 8月以来&#xff0c;上市新…

Docker容器无法启动 Cannot find /usr/local/tomcat/bin/setclasspath.sh

报错信息如下 解决办法 权限不够 加上--privileged 获取最大权限 docker run --privileged --name lenglianerqi -p 9266:8080 -v /opt/docker/lenglianerqi/webapps:/usr/local/tomcat/webapps/ -v /opt/docker/lenglianerqi/webapps/userfile:/usr/local/tomcat/webapps/u…

三洋、松下、索尼命运为何不同 ?一个主品牌竞争优势决定长期胜出

在当前高度竞争的市场环境中&#xff0c;尽管都是链主品牌&#xff0c;主品牌竞争优势的强弱将决定它们在竞争中取得成功的可能性。这一点可以从三洋、松下、索尼三个品牌的发展历程中得到印证。三者中在主品牌认知层面&#xff0c;索尼是科技品牌、松下是国家品牌、三洋是国民…

视频汇聚/视频云存储/视频监控管理平台EasyCVR提升网络稳定小tips来啦!

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

银河麒麟服务器v10 sp1 .Net6.0 上传文件错误 access to the path is denied

上一篇&#xff1a;银河麒麟服务器v10 sp1 部署.Net6.0 http https_csdn_aspnet的博客-CSDN博客 .NET 6之前&#xff0c;在Linux服务器上安装 libgdiplus 即可解决&#xff0c;libgdiplus是System.Drawing.Common原生端跨平台实现的主要提供者&#xff0c;是开源mono项目。地址…

技术文档如何在线搭建网页形式,方便编辑与管理分享其他人员?

搭建在线技术文档网页形式的平台可以方便编辑、管理和分享给其他人员&#xff0c;促进团队的协作和知识共享。 搭建在线技术文档网页形式的步骤和具体操作的详细介绍&#xff1a; 1. 选择适合的平台 首先&#xff0c;需要选择适合搭建在线技术文档网页形式的平台。市面上有很…