数据结构课程设计-哈夫曼编码译码

//********************************************
//程序功能:哈夫曼编码及译码
//
//日期:2014年11月18
//
//********************************************
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <windows.h>

#define MAX 128             //叶子节点个数(对应ASCII码)
#define M 2*MAX-1           //树的节点个数

typedef struct node{
	int weight;				//权值
	int parent;				//双亲位置
	int LChild;				//左孩子位置
	int RChild;				//右孩子位置
}HTNode,HuffmanTree[M+1];
typedef struct Node{
	char letter;//字符
	char* code;//编码
	int w;//权值(对应文章中字母(letter)出现次数)
}Huffman[MAX+1];

HuffmanTree ht;					//存储哈夫曼树
Huffman qz;						//权值相关信息
int weight[M+1]={0};			//存储临时权值
int t=0;						//存储叶子节点个数

/*********************函数声明**********************/
void select(int *s1,int *s2);//建立哈夫曼树时的选择权值

int ReadWeight();//从文件中读文章获得权值,返回权值个数

void CrtHuffmanTree();//建立哈夫曼树

void Encoding();//编码

void Print();//打印

void WriteTree();//向文件中写入哈夫曼树

void Initialization();//初始化

void WriteCode();//向文件中写入编码

void Decoding();//译码

int find_letter(char ch);//查找字符

int find_code(char s[]);//查找编码

void InitTree();//初始化树

void TreePrinting();//打印哈夫曼树

void Menu();//菜单

void load();//loading

void _print(FILE *fp,node hft,int n);

//主函数
int main()
{
	Menu();//调用菜单,完成一系列工作
	return 0;
}

void Menu()
{
	char chose;
	load();
	InitTree();
	printf("**************************Menu*************************\n");
	printf("******初始化(I)***********编码(E)********译码(D)*******\n");
	printf("****打印代码文件(P)***打印哈夫曼树(T)****退出(O)*******\n");
	printf("*******************************************************\n");
	while(true){
		printf("请选择:");
		scanf("%c",&chose);
		getchar();//除去回车
		switch(chose){
		case 'I':Initialization();break;		//初始化
		case 'E':Encoding();break;				//对叶子节点进行编码
		case 'D':Decoding();break;				//译码
		case 'P':Print();break;					//打印编码
		case 'T':TreePrinting();break;			//打印哈夫曼树
		case 'O':
			printf("要退出了哦!\n");			//退出提醒
			Sleep(2000);						//挂起
			exit(1);							//退出程序
		default:printf("怎么能选错呢!\n");
		}
	}
}

//loading
void load()
{
	printf("loading");
	for(int i=1;i<=10;i++){
		printf(".");
		Sleep(500);
	}
	printf("\n就要进入啦!\n");
	Sleep(2000);
}
//初始化树
void InitTree()
{
	ht[0].weight = 0;//标志哈夫曼树是否存在
	qz[0].w = 0;	//标志是否编码
}
//初始化
void Initialization()
{
	ht[0].weight = 1;		//初始化标志,说明哈夫曼树以存在
	t=ReadWeight();			//读取权值
	CrtHuffmanTree();		//建立哈夫曼树
	WriteTree();			//将哈夫曼树写入文件
	printf("耶!'初始化'成功啦!\n");
}
//将哈夫曼树写入文件
void WriteTree()
{
	FILE *fp;//hfmTree 文件指针
	int m=2*t-1;
	int i;

	//打开文件
	if((fp=fopen("F:\\hfmTree.txt","w")) == NULL){
		printf("open hfmTree.txt--file error\n");
		exit(0);
	}//else printf("open hfmTree.txt--file sucess!\n");
	//哈夫曼树写入文件
	for(i=1;i<=m;i++)
		fprintf(fp,"%d %d %d %d\n",ht[i].weight,ht[i].parent,ht[i].LChild,ht[i].RChild);
	//关闭文件
	if(fclose(fp)){
		printf("close hfmTree.txt--file error!\n");
		exit(0);
	}//else printf("close hfmTree.txt--file success!\n");
}
//选择s1,s2
void select(int n,int *s1,int *s2)
{
	int i;
	int min;
	//寻找一个没有双亲的节点,找到后退出循环
	for(i=1; i<=n; i++){
		if(ht[i].parent == 0){
			min = i;
			break;
		}
	}
	//寻找最小无双亲节点
	for(i=1; i<=n; i++){
		if(ht[i].weight<ht[min].weight && ht[i].parent == 0)
			min = i;
	}
	*s1 = min;
	//寻找次最小无双亲节点
	for(i=1; i<=n; i++){
		if(ht[i].parent == 0 && i != *s1){
			min = i;
			break;
		}
	}
	for(i=1; i<=n; i++){
		if(ht[i].weight < ht[min].weight && i != *s1 && ht[i].parent == 0)
			min = i;
	}
	*s2 = min;

}
//读取文章,获取权值
int ReadWeight()//返回权值个数
{
	int n=1;
	FILE *fp;
	char ch;

	//打开文件
	if((fp=fopen("F:\\ToBeTran.txt","r")) == NULL){
		printf("Open ToBeTran.txt--file error!\n");
		exit(0);
	}//else printf("open ToBeTran.txt--file sucess!\n");

	//读取字符
	while(!feof(fp)){//一直循环,知道文件结束
		ch = fgetc(fp);
		if(ch != EOF){
			weight[ch]++;
		}
	}

	//关闭文件
	if(fclose(fp)){
		printf("close ToBeTran.txt--file error!\n");
		exit(0);
	}//else printf("close ToBeTran.txt--file success!\n");

	//临时权值转化到qz[]中
	for(int i=0;i<M;i++){
		//printf("%d ",weight[i]);
		if(weight[i]>=1){
			qz[n].letter = (char)i;
			qz[n].w = weight[i];
			n++;
		}
	}
	return n-1;//n从1开始计数
}

//建立哈夫曼树
void CrtHuffmanTree()
{
	int i,s1,s2,m = 2*t-1;
	//*初始化*//
	for(i=1; i<=t; i++){//第1到n个位置放置n个叶子节点
		ht[i].weight = qz[i].w;
		ht[i].parent = ht[i].LChild = ht[i].RChild = 0;
	}
	for(i=t+1;i<=m;i++){//第n+1个到第m个位置放置非叶子节点
		ht[i].weight = ht[i].parent = ht[i].LChild = ht[i].RChild = 0;
	}

	//*建立*//
	for(i=t+1; i<=m; i++){
		select(i-1,&s1,&s2);
		//printf("s1 = %d,s2 = %d\n",s1,s2);
		ht[i].weight = ht[s1].weight + ht[s2].weight;
		ht[s1].parent = ht[s2].parent = i;
		ht[i].LChild = s1;
		ht[i].RChild = s2;
	}

}
//哈夫曼编码
void Encoding()
{
	if(ht[0].weight == 0){
		printf("哇哦!!居然没初始化!!\n");
		Sleep(2000);//挂起一段时间
		return;
	}
	int i,start,c,p;
	char *cd;
	cd = (char*)malloc(t*sizeof(char));
	cd[t-1]='\0';
	for(i=1; i<=t; i++){//对n个叶子节点进行编码
		start = t-1;//定位到临时编码数组的最后一位
		c = i;//记录当前节点位置
		p = ht[i].parent;//记录当前节点的双亲位置
		while(p!=0){
			--start;
			if(ht[p].LChild == c)//若该节点是其双亲的左孩子,则编码0
				cd[start]='0';
			else//若为右孩子则编码1
				cd[start]='1';
			c = p;//下次循环的准备条件
			p = ht[p].parent;
		}
		qz[i].code=(char*)malloc((t-start)*sizeof(char));
		strcpy(qz[i].code,&cd[start]);
	}
	free(cd);

	//以上代码完成编码工作

	/*测试代码
	for(i=1;i<=n;i++)
	printf("%c %d %s\n",hc[i].letter,hc[i].w,hc[i].code);*/
	//将编码写入文件
	WriteCode();
	/*for(i=1;i<=n;i++){
	printf("%s\n",hc[i].code);
	}*/
	qz[0].w = 1;//标志以编码
	printf("耶!'编码'成功啦!\n");
}

//编码写入函数
void WriteCode()
{
	FILE *fp_code,*fp_text;
	char ch;
	int i;
	//打开编码存储文件
	if((fp_code=fopen("F:\\CodeFile.txt","w")) == NULL){
		printf("open CodeFile.txt--file error !\n");
		exit(0);
	}//else printf("open CodeFile.txt--file success!\n");

	//打开需要编码的文本文件
	if((fp_text=fopen("F:\\ToBeTran.txt","r")) == NULL){
		printf("open ToBeTran.txt--file error !\n");
		exit(0);
	}//else printf("open ToBeTran.txt--file success!\n");

	while(!feof(fp_text)){
		ch = fgetc(fp_text);
		//printf("%c ",ch);
		i = find_letter(ch);
		//printf("i = %d\n",i);
		if(i!=0)
			fprintf(fp_code,"%s ",qz[i].code);
	}

	//关闭文件
	if(fclose(fp_code)){
		printf("close CodeFile.txt--file error!\n");
		exit(0);
	}//else printf("close CodeFile.txt--file success !\n");
	if(fclose(fp_text)){
		printf("close ToBeTran.txt--file error!\n");
		exit(0);
	}//else printf("close ToBeTran.txt--file success !\n");
}

//查找字符
int find_letter(char ch)
{
	int low,high,i;
	low = 1;high = t;
	//二分查找
	while(high - low >= 0){
		i=(low+high)/2;
		if(qz[i].letter == ch)
			return i;
		else if(qz[i].letter < ch){
			low = i+1;
		}
		else
			high = i-1;
	}
	return 0;
}
//打印哈夫曼树的节点权值
void Print()
{
	if(ht[0].weight == 0){
		printf("哇哦!!居然没初始化!\n");
		Sleep(2000);//挂起一段时间
		return;
	}
	if(qz[0].w == 0){
		printf("哇塞!!居然没编码!!\n");
		Sleep(2000);
		return;
	}
	int i=0;
	char code[100];
	FILE *fp_r,*fp_w;
	if((fp_r=fopen("F:\\CodeFile.txt","r")) == NULL){
		printf("open CodeFile.txt--file error!\n");
		exit(0);
	}//else printf("open CodeFile.txt success!\n");
	if((fp_w=fopen("F:\\CodePrint.txt","w")) == NULL){
		printf("open CodePrint.txt--file error!\n");
		exit(0);
	}//else printf("open CodePrint.txt success!\n");
	while(!feof(fp_r)){
		fscanf(fp_r,"%s\n",code);
		printf("%s ",code);
		fprintf(fp_w,"%s",code);
		i++;
		if(i%5 == 0){
			printf("\n");
			fprintf(fp_w,"\n");
		}
	}
	printf("耶!'打印'成功啦!\n");
}

//译码
void Decoding()
{
	if(ht[0].weight == 0){
		printf("哇哦!!居然没初始化!\n");
		Sleep(2000);//挂起一段时间
		return;
	}
	if(qz[0].w == 0){
		printf("哇塞!!居然没编码!!\n");
		Sleep(2000);//挂起一段时间
		return;
	}
	char code[100];
	FILE *fp_r,*fp_w;
	int i;
	//打开CodeFile.txt文件,从中读取编码
	if((fp_r=fopen("F:\\CodeFile.txt","r")) == NULL){
		printf("open CodeFile.txt--file error!\n");
		exit(0);
	}//else printf("open CodeFile.txt success!\n");

	//打开TextFile.txt文件,存储翻译的内容
	if((fp_w=fopen("F:\\TextFile.txt","w")) == NULL){
		printf("open TextFile.txt--file error!\n");
		exit(0);
	}//else printf("open TextFile.txt success!\n");

	while(!feof(fp_r)){
		fscanf(fp_r,"%s\n",code);
		i = find_code(code);
		if(i!=0)
			fprintf(fp_w,"%c",qz[i].letter);
	}
	if(fclose(fp_r)){
		printf("close CodeFile.txt--file error!\n");
		exit(0);
	}//else printf("close CodeFile.txt--file success !\n");
	if(fclose(fp_w)){
		printf("close TextFile.txt--file error!\n");
		exit(0);
	}//else printf("close TextFile.txt--file success !\n");
	printf("耶!'译码'成功啦!\n");
}

int find_code(char s[])//查找编码
{
	int i;
	for(i=1;i<=t;i++){
		if(strcmp(qz[i].code,s) == 0)
			return i;
	}
	return 0;
}

void TreePrinting()
{
	if(ht[0].weight == 0){
		printf("哇哦!!居然没初始化!\n");
		Sleep(2000);//挂起一段时间
		return;
	}
	FILE *fp;
	int i,r=t*2-1;
	//打开文件
	if((fp=fopen("F:\\TreePrint.txt","w")) == NULL){
		printf("open CodeFile.txt--file error !\n");
		exit(0);
	}
	for(i=1;i<=r;i++){
		if(ht[i].parent == 0)
			break;
	}
	//printf("%d\n",ht[i].parent );
	_print(fp,ht[i],0);
	if(fclose(fp)){
		printf("close hfmTree.txt--file error!\n");
		exit(0);
	}
	printf("耶!'打印'成功啦!\n");
}
//哈夫曼树纵向显示并写入文件
void _print(FILE *fp,node hft,int n)
{
	if(hft.LChild == 0 && hft.RChild == 0){
		for(int i=0;i<n;i++){
			printf(" ");
			fprintf(fp," ");
		}
		printf("%-6d\n",hft.weight);
		fprintf(fp,"%-6d\n",hft.weight);
		return ;
	}
	_print(fp,ht[hft.RChild],n+2);
	for(int i=0;i<n;i++){
		printf(" ");
		fprintf(fp," ");
	}
	printf("%-6d\n",hft.weight);
	fprintf(fp,"%-6d\n",hft.weight);
	_print(fp,ht[hft.LChild],n+2);
}

时间: 2024-10-07 06:36:32

数据结构课程设计-哈夫曼编码译码的相关文章

哈夫曼编码译码系统(c/c++)

哈夫曼编码译码系统的实现,主要包含三部分: 1.创建哈夫曼树 2.编码函数 3.译码函数 编写代码时为了方便,在这里混用了c++的输入输出流.主体用c语言实现. 下面时代码部分: 1.头文件,以及储存结构: #include<stdio.h> #include<iostream> using namespace std; #define MAX 2000 typedef char ElemType; typedef struct{ ElemType data; int w; int

基于python的二元霍夫曼编码译码详细设计

一.设计题目 对一幅BMP格式的灰度图像(个人证件照片)进行二元霍夫曼编码和译码 二.算法设计 (1)二元霍夫曼编码: ①:图像灰度处理: 利用python的PIL自带的灰度图像转换函数,首先将彩色图片转为灰度的bmp图像,此时每个像素点可以用单个像素点来表示. ②:二元霍夫曼编码: 程序流程图: 详细设计: 统计像素点频率,首先通过python自带的PIL库的图像像素点读取函数read()获取灰度图像的所有像素点,通过循环遍历每个像素点,将每个出现的像素点值以及其次数以键值对的形式放入到pyt

(编程训练)再回首,数据结构——哈夫曼编码的实现

最近在复习数据结构,顺便看看大一的时候写的代码,看完之后比当初有了更加深刻的体会. 希望这些能提供给初学者一些参考. 在VC++6.0下可运行,当初还写了不少注释. [问题描述] 根据给定字符的使用频率,为其设计哈夫曼编码 [基本要求] ·功能:求出n个字符的哈夫曼编码 ·输入:输入n个字符和字符在电文中的使用频率 ·输出:n个字符的哈夫曼编码 [模块划分] 1.    初始化哈夫曼树函数 InitHuffmanTree() 2.    输入权值函数 InputWeight() 3.    选择

哈夫曼编码课程设计+最小优先对列建树。

问题描述 利用赫夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本.这要求在发送端通过一个编码系统对待传输数据预先编码,在接收端将传来的数据进行译码(复原).对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统.试为这样的信息收发站编写一个赫夫曼码的编/译码系统. 基本要求 一个完整的系统应具有以下功能: (1) I:初始化(Initialization).从终端读入字符集大小n,以及n个字符和n个权值,建立赫夫曼树,并将它存于文件hfmTree中. (

【数据结构与算法】二叉树——哈夫曼编码

最近有很多的小朋友问我什么是哈夫曼编码,哈夫曼编码是一种可变字长的编码,那什么是可变字长呢?就是一句话里的每一个字符(ASCII码)它的位数(长度)是不一样的.就像我们一句话(AAAACCCCCDDDDBBE)有A,B,C,D,E五种字符,在这里我们可以用01表示A字符,用001表示B字符,用11表示C字符,用10表示D字符,用000表示E字符.如下图: 既然知道了哈夫曼编码是什么了,那又有好奇的小朋友又会问了:那么哈夫曼编码是按照什么原理生成的呢? 在这里我就要告诉大家,哈夫曼编码是根据哈夫曼

20182327 2019-2020 《程序设计与数据结构》哈夫曼编码测试报告

20182327 2019-2020 <程序设计与数据结构>哈夫曼编码测试报告 课程:<程序设计与数据结构> 班级: 1823 姓名:赵天昊 学号:20182327 实验教师:王志强 实验日期:2019年11月17日 必修/选修: 必修 教材中的哈夫曼树 1.在计算机数据处理中,哈夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现机率的方法得到的,出现机率高的字母使用较短的编码,反之出现机率低的则使用较长的编码,这便使编码之后的字

哈夫曼编码和译码

构建哈夫曼原理:(每个元素都是叶子结点,N 个元素共有 2N-1 个结点) 有 N 个带权值的结点,将其按以下方法构建:①②③ ①选取 N 个结点集合中最小的两个权值结点构造成一个新的二叉树,且设置新结点的权值为左右孩子权值之和 ②将以上选取的两个最小权值结点从原集合中删除,向集合中加入 这两个结点的跟,即 1 中创建的新结点,此时集合 元素为 N = N - 2 + 1;  ③重复 ① ② 直到只剩下一个结点,该结点就是构建的二叉树的根 哈夫曼编码原理: 在哈夫曼树中,凡是左分支,即左孩子的全

哈弗曼树的构建,哈夫曼编码、译码

哈夫曼树的基本概念 哈夫曼树(Huffman Tree),又叫最优二叉树,指的是对于一组具有确定权值的叶子结点的具有最小带权路径长度的二叉树. (1)路劲(Path):从树中的一个结点到另一个结点之间的分支构成两个结点间的路径. (2)路径长度(Path Length):路径上的分支树. (3)树的路径长度(Path Length of Tree):从树的根结点到每个结点的路径长度之和.在结点数目相同的二叉树中,完全二叉树的路径长度最短. (4)结点的权(Weight of  Node):在一些

【数据结构】树与树的表示、二叉树存储结构及其遍历、二叉搜索树、平衡二叉树、堆、哈夫曼树与哈夫曼编码、集合及其运算

1.树与树的表示 什么是树? 客观世界中许多事物存在层次关系 人类社会家谱 社会组织结构 图书信息管理 分层次组织在管理上具有更高的效率! 数据管理的基本操作之一:查找(根据某个给定关键字K,从集合R 中找出关键字与K 相同的记录).一个自然的问题就是,如何实现有效率的查找? 静态查找:集合中记录是固定的,没有插入和删除操作,只有查找 动态查找:集合中记录是动态变化的,除查找,还可能发生插入和删除 静态查找--方法一:顺序查找(时间复杂度O(n)) int SequentialSearch(St