数据结构-哈夫曼树实验

目录

一、实验目的

二、问题描述

三、需求分析

四、方法描述

五、代码实现

六、实验结果测试


一、实验目的

熟悉非线性结构的特点 , 掌握非线性结构的存储方式及各种操作的实现方法,同时对自顶向下的程序设计方法、应用程序界面的设计、非线性结构的文件存储方法等方面的辑程技术进行训练。

二、问题描述

利用哈夫曼编码进行信息通讯可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对待传数据预先编码;在接收端将传来的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统,试为这样的信息收发站写一个哈夫曼编译码系统。

三、需求分析

一个完整的系统应具有以下功能:

(1) I: 初始化。从终端读字符集大小 n ,及 n 个字符和 n 个权值,建立哈夫曼树,并将其存于文件hfmtree中。

(2) C: 编码。利用已建好的哈夫曼树(如不在内存,则从文件hfmtree中读入),对文件tobetrans中的正文进行编码,然后将结果存入文件codefile中。

(3) D: 译码。利用已建好的哈夫曼树将文件codefile中的代码进行译码,结果存入文件textfile中。

(4) P: 打印代码文件。将文件codefi1e以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件codeprint中。

(5) T:打印哈夫曼树。将已在内存中的哈夫曼树以直观的方式显示在屏幕上,同时将此字符形式的哈夫曼树写入文件treeprint中。

(6) E: 表示结束运性行结束,用户键入一个选择功能字符,则执行相应的功能,此功能执行完毕后再显示此菜单,直至用户选择了“E”为止。

四、方法描述

typedef struct

{

   char alphabet;

   int weight;

   int parent,lch,rch;

}HTNode,*HuffmanTree;

为哈夫曼树结构体

初始化时,输入哈夫曼树叶子节点所代表的字符和字符频度。遍历哈夫曼树,利用select函数找到权值最小的两个值,作为叶子节点,后再寻找其双亲结点,直至根节点。还要根据哈夫曼树形成哈夫曼编码表,从哈夫曼树的第一行开始遍历,找到该叶子节点对应的双亲结点直到根节点,根据左右孩子确定编码的0,1存储到cd数组中,最终形成该字符对应的哈夫曼编码存储到HC二维数组中。

五、代码实现

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int n;
typedef struct
{
	char alphabet;
	int weight;
	int parent,lch,rch;
}HTNode,*HuffmanTree;

typedef char **HuffmanCode;

char enterChoice();
void makeTree(HuffmanTree &HT,HuffmanCode &HC);//建立哈夫曼树 
void Select(HuffmanTree &HT,int i,int* s1,int* s2); 
void coding(HuffmanTree &HT,HuffmanCode &HC);//编码 
void decode(HuffmanTree &HT,HuffmanCode &HC);//译码 
void printCode();//打印代码文件 
void printTree(HuffmanTree &HT,HuffmanCode &HC);//打印哈夫曼树 

int main()
{
	char choice;
	HuffmanTree HT;
	HuffmanCode HC;
	while((choice=enterChoice())!='E')
	{
		switch(choice)
		{
			case 'I':
				//初始化 
				makeTree(HT,HC);
				break;
			case 'C':
				//编码 
				coding(HT,HC);
				break;
			case 'D':
				//译码 
				decode(HT,HC);
				break;
			case 'P':
				//打印代码文件 
				printCode();
				break;
			case 'T':
				//打印哈夫曼树 
				printTree(HT,HC);
				break;
		}
		getchar();
	}
	return 0;
}


/*用户菜单选择*/
char enterChoice()
{
	char menuChoice;//存储用户菜单的选择
	
	/*显示可选的菜单*/ 
	printf("请输入您的选择\n");
	printf("I-初始化\n");
	printf("C-编码\n");
	printf("D-译码\n");
	printf("P-打印代码文件\n");
	printf("T-打印哈夫曼树\n");
	printf("E-退出系统\n");
	menuChoice=getchar();//接受用户选择
	return menuChoice; 
}

/*构建哈夫曼树*/
void makeTree(HuffmanTree &HT,HuffmanCode &HC)
{
	char *cd,al;
	int m,i,s1,s2;
	printf("请输入n的值\n"); 
	scanf("%d",&n);//点数 
	if(n<=1) return;
	/*初始化哈夫曼树*/
	m=2*n-1;//边数=点数*2-1 
	HT=new HTNode[m+1];
	for(i=1;i<=m;++i) 
	{
		HT[i].lch=0;
		HT[i].rch=0;
		HT[i].parent=0;
	}
	for(i=1;i<=n;i++)
	{
		getchar();
		printf("请输入字符\n"); 
		al=getchar();
		HT[i].alphabet=al;
		printf("请输入字符频度\n"); 
		scanf("%d",&HT[i].weight);
	}
	for(i=n+1;i<=m;i++)
	{
		Select(HT,i-1,&s1,&s2);
		HT[s1].parent=i;
		HT[s2].parent=i;
		HT[i].lch=s1;
		HT[i].rch=s2;
		HT[i].weight=HT[s1].weight+HT[s2].weight;
	}
	printf("哈夫曼树构建成功!\n");
	/*生成哈夫曼编码*/ 
	int start,c,f;
	HC=(HuffmanCode)malloc((n+1)*sizeof(char*));
	cd=(char*)malloc(n*sizeof(char));
	cd[n-1]='\0';
	for(i=1;i<=n;i++)
	{
		start=n-1;
		for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent)
		{
			if(HT[f].lch==c)
			{
				cd[--start]='0';
			}
			else
			{
				cd[--start]='1';
			}
		}
		HC[i]=(char*)malloc((n-start)*sizeof(char));
		strcpy(HC[i],&cd[start]);
	}
	printf("哈夫曼编码表建立成功!\n");
	free(cd);
}

/*找出权值最小的两个结点*/
void Select(HuffmanTree &HT,int i,int* s1,int* s2)
{
	int j,S1=0,S2=0;
	for(j=1;j<=i;j++)
	{
		if(HT[j].parent!=0)
		{
			continue;
		}
		if(S1==0&&S2==0)
		{
			S1=HT[j].weight;
			S2=HT[j].weight;
			*s1=j;
			*s2=j;
		}
		else if(S1==S2)
		{
			if(HT[j].weight<S1)
			{
				S1=HT[j].weight;
				*s1=j;
			}
			else
			{
				S2=HT[j].weight;
				*s2=j;
			}
		}
		else
		{
			if(HT[j].weight<S1)
			{
				S2=S1;
				*s2=*s1;
				S1=HT[j].weight;
				*s1=j;
			}
			else if(HT[j].weight<S2)
			{
				S2=HT[j].weight;
				*s2=j;
			}
		}
	}
}

/*编码*/ 
void coding(HuffmanTree &HT,HuffmanCode &HC)
{
	int i,l;
	FILE *fpTobe;//正文文件 
	FILE *fpCode;//编码文件 
	char test[30];//测试数据 
	char data;
	/*输入测试数据文件*/
	if((fpTobe=fopen("tobrtrans.dat","ab+"))==NULL)//打开编码文件 
	{
		printf("文件有误\n");
		exit(0);
	}
	printf("输入测试数据文件");
	scanf("%s",test);
	fseek(fpTobe,0,SEEK_END);
	fwrite(&test,(29*sizeof(char)),1,fpTobe);
	printf("测试数据录入完成!\n");
	fclose(fpTobe);
	/*测试输入完成*/
	if((fpTobe=fopen("tobrtrans.dat","rb"))==NULL)//打开正文文件 
	{
		printf("文件为空\n");
	}
	if((fpCode=fopen("codefile.dat","ab+"))==NULL)//打开编码文件 
	{
		printf("文件有误\n");
		exit(0);
	}
	while((fread(&data,sizeof(char),1,fpTobe))!=(int)NULL)
	{
		for(i=1;i<=n;i++)
		{
			if(HT[i].alphabet==data)
			{
				l=strlen(HC[i]);
				fseek(fpCode,0,SEEK_END);
				fwrite(HC[i],(l*sizeof(char)),1,fpCode);
				break;
			}
		}
	}
	printf("正文文件编码成功!\n");
	fclose(fpTobe);
	fclose(fpCode);
}

/*译码*/
void decode(HuffmanTree &HT,HuffmanCode &HC)
{
	int i,m,res=0;
	FILE *fpDecode;//正文文件 
	FILE *fpCode;//编码文件 
	char data,DATA[n];
	if((fpDecode=fopen("textfile.dat","ab+"))==NULL)//打开正文文件 
	{
		printf("文件有误\n");
		exit(0);
	}
	if((fpCode=fopen("codefile.dat","rb"))==NULL)//打开编码文件 
	{
		printf("文件为空\n");
	}
	strcpy(DATA,"\0");
	while((fread(&data,sizeof(char),1,fpCode))!=(int)NULL)
	{
		strncat(DATA,&data,1);
		for(i=1;i<=n;i++)
		{
			m=strcmp(HC[i],DATA);
			if(m==0)
			{
				res=1;
				break;
			}
		}
		if(res==1)
		{
			fseek(fpDecode,0,SEEK_END);
			fwrite(&HT[i].alphabet,sizeof(char),1,fpDecode);
			strcpy(DATA,"\0");
			res=0;
		}
	}
	printf("编码文件译码成功!\n");
	fclose(fpDecode);
	fclose(fpCode);
}

/*打印代码文件*/
void printCode()
{
	int i=0;
	FILE *fpCode;
	char data;
	if((fpCode=fopen("codefile.dat","rb"))==NULL)//打开编码文件 
	{
		printf("文件为空\n");
	}
	else
	{
		while((fread(&data,sizeof(char),1,fpCode))!=(int)NULL)
		{
			printf("%c",data);
			i++;
			if(i%50==0)
			{
				printf("\n");
			}
		}
	}
	fclose(fpCode);
	printf("\n");
	printf("编码文件打印成功!\n");
}

/*打印哈夫曼树*/
void printTree(HuffmanTree &HT,HuffmanCode &HC)
{
	int i;
	printf("哈夫曼树\n");
	printf("%-5s%-5s%-5s%-6s%-6s\n","字符","权值","双亲","左孩子","右孩子"); 
	for(i=1;i<=(2*n-1);i++)
	{
		printf("%-5c%-5d%-5d%-6d%-6d\n",HT[i].alphabet,HT[i].weight,HT[i].parent,HT[i].lch,HT[i].rch);
	}
	printf("哈夫曼树打印成功!\n");
}

六、实验结果测试

主菜单选择:

进行初始化:

编码:

译码:

打印代码文件

打印哈夫曼树

  • 18
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个简单的哈夫曼树实验的C语言代码示例: ```c #include <stdio.h> #include <stdlib.h> #define MAX_LEAF_NODE 100 typedef struct huffman_node { int weight; struct huffman_node *left_child; struct huffman_node *right_child; } HuffmanNode; // 初始化叶子节点 void init_leaf_nodes(HuffmanNode **leaf_nodes, int *weights, int n) { for (int i = 0; i < n; i++) { leaf_nodes[i] = (HuffmanNode *) malloc(sizeof(HuffmanNode)); leaf_nodes[i]->weight = weights[i]; leaf_nodes[i]->left_child = NULL; leaf_nodes[i]->right_child = NULL; } } // 合并两个节点为一个新节点 HuffmanNode *merge_nodes(HuffmanNode *node1, HuffmanNode *node2) { HuffmanNode *new_node = (HuffmanNode *) malloc(sizeof(HuffmanNode)); new_node->weight = node1->weight + node2->weight; new_node->left_child = node1; new_node->right_child = node2; return new_node; } // 建立哈夫曼树 HuffmanNode *build_huffman_tree(HuffmanNode **leaf_nodes, int n) { while (n > 1) { // 找到权值最小的两个节点 int min_index1 = 0, min_index2 = 1; if (leaf_nodes[min_index1]->weight > leaf_nodes[min_index2]->weight) { min_index1 = 1; min_index2 = 0; } for (int i = 2; i < n; i++) { if (leaf_nodes[i]->weight < leaf_nodes[min_index1]->weight) { min_index2 = min_index1; min_index1 = i; } else if (leaf_nodes[i]->weight < leaf_nodes[min_index2]->weight) { min_index2 = i; } } // 合并两个节点 HuffmanNode *new_node = merge_nodes(leaf_nodes[min_index1], leaf_nodes[min_index2]); leaf_nodes[min_index1] = new_node; leaf_nodes[min_index2] = leaf_nodes[n - 1]; n--; } return leaf_nodes[0]; } // 打印哈夫曼编码 void print_huffman_code(HuffmanNode *node, int *code, int depth) { if (node->left_child == NULL && node->right_child == NULL) { printf("node weight: %d, code: ", node->weight); for (int i = 0; i < depth; i++) { printf("%d", code[i]); } printf("\n"); return; } code[depth] = 0; print_huffman_code(node->left_child, code, depth + 1); code[depth] = 1; print_huffman_code(node->right_child, code, depth + 1); } int main() { int n; printf("Please input the number of leaf nodes: "); scanf("%d", &n); if (n <= 0 || n > MAX_LEAF_NODE) { printf("Invalid input!\n"); return 0; } int *weights = (int *) malloc(n * sizeof(int)); HuffmanNode **leaf_nodes = (HuffmanNode **) malloc(n * sizeof(HuffmanNode *)); printf("Please input the weights of leaf nodes: "); for (int i = 0; i < n; i++) { scanf("%d", &weights[i]); } init_leaf_nodes(leaf_nodes, weights, n); HuffmanNode *root_node = build_huffman_tree(leaf_nodes, n); int *code = (int *) malloc(n * sizeof(int)); print_huffman_code(root_node, code, 0); return 0; } ``` 在这个代码示例中,我们定义了一个HuffmanNode结构体表示哈夫曼树中的节点。另外,我们首先初始化叶子节点,然后依次合并两个权值最小的节点构建哈夫曼树,最后输出每个叶子节点的哈夫曼编码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值