【数据结构实验】哈夫曼树

这篇具有很好参考价值的文章主要介绍了【数据结构实验】哈夫曼树。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【数据结构实验】哈夫曼树

简介:

为一个信息收发站编写一个哈夫曼码的编/译码系统。文末贴出了源代码。

需求分析

  1. 完整的系统需要具备完整的功能,包含初始化、编码、译码、印代码文件和印哈夫曼树,因此需要进行相应的文件操作进行配合。
  2. 哈夫曼树的字符集和频度可以从文件中读入,也可以让用户手动输入,应当给予用户足够的选择。
  3. 测试数据(附后)。

概要设计

  1. 抽象数据类型树的定义如下:
ADT BinaryTree{
 数据对象D:D是具有相同特性的数据元素集合。
 数据关系R:如D=Ф,则R=Ф,称BinaryTree为空二叉树;
 如D≠Ф,则R={H},H是如下二元关系:
(1) 在D中存在唯一的称为根的数据元素root,它在关系H下无前驱;
(2)如D-{root}≠Ф,则存在D-{root}={D1,Dr},且D1∩Dr=Ф;3)如D1≠Ф,则D1中存在唯一元素x1,1>∈H,且存在D1上的关系H1∈H;如Dr≠Ф,则Dr中存在唯一的元素xr,r>∈H,且存在Dr上的关系Hr包含于H;H={1>,r>,H1,Hr};
(4(D1,{H1})是一棵符合本定义的二叉树,称为根的右子树。
基本操作 P:
InitBiTree(&T)                      操作结果:构造空二叉树T.
DestroyBiTree(&T);                    初始条件:二叉树T存在。
操作结果:销毁二叉树T.
CreateBiThrTree(&T);
操作结果:先序构造二叉树T,Ltag和RTag初始置为Link.
PreOrderTraverse(T );
初始条件:二叉树T存在。
操作结果:先序递归遍历T。
InOrderTraverse(T);
初始条件:二叉树T存在。
操作结果:中序递归遍历T。
PostOrderTraverse(T);
初始条件:二叉树T存在。
操作结果:后序递归遍历T。
InOrderThreading(&ThrT, T);
初始条件:二叉树T存在。
操作结果:建立头结点ThrT,并调用InThreading(T);函数。
InThreading(T);
初始条件:二叉树T存在。
操作结果:中序线索化二叉树T;
InOrderTrasverse_Thr(T);
初始条件:二叉树T存在。
操作结果:中序扫描线索化的二叉树。
}ADT BinaryTree
  1. 主程序
int main()
{
			初始化;
		do{
			接受命令;
			处理命令;
     }while(“命令”!=“退出”)
}
  1. 调用关系
    本程序共有七个模块,调用关系简单。主函数模块可以调用任意模块,在编码和译码模块,在哈夫曼树不存在的情况下允许调用读取哈夫曼树模块。

详细设计

  1. 哈夫曼树的类型
typedef struct
{
	unsigned int weight;  //权重
	char alpha;   //字母
	int number;  //编号
	unsigned int parent,lchild,rchild; //左右孩子和双亲
}HTNode,*HuffmanTree;   //哈夫曼树结点和指针类型
typedef char** HuffmanCode;  //哈夫曼编码类型
  1. 哈夫曼树的基本操作如下
void Select(HuffmanTree HT, int end, int *s1, int *s2);
//构建哈夫曼树子函数,筛选权重最小的项 
int GetHuffmanRoot(HuffmanTree HT);
//返回树根节点下标 
Status HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, char* alpha,int *w, int n);
//构建哈夫曼树
Status saveTreeFrequent(HuffmanTree HT, HuffmanCode HC,int length);
//保存权重 
Status Encoding(HuffmanTree &HT,HuffmanCode &HC,int length);
//编码 
Status read(char *alpha,int *frequent,int length);
//读取字符及其权重 
Status Decoding(HuffmanTree HT,HuffmanCode HC,int length);
//解码 
Status Print();//印码
Status writeTree(HuffmanTree HT,unsigned root,int level,FILE *fs);
//画树子函数 
Status PrintTree(HuffmanTree HT,unsigned root,int level);
//画树
  1. 源代码
/*头文件*/ 
#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<math.h>
using namespace std;

/*宏定义*/
#define OK 1
#define TRUE 1
#define ERROR -1
#define FALSE -1

/*哈夫曼树定义*/
typedef struct
{
	unsigned int weight;
	char alpha;
	int number;
	unsigned int parent,lchild,rchild;
}HTNode,*HuffmanTree;
typedef char** HuffmanCode;
typedef int Status;

/*函数声明*/
void onScreen ();
void Select(HuffmanTree HT, int end, int *s1, int *s2);//构建哈夫曼树子函数,筛选权重最小的项 
int GetHuffmanRoot(HuffmanTree HT);//返回树根节点下标 
Status HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, char* alpha,int *w, int n);//构建哈夫曼树
Status saveTreeFrequent(HuffmanTree HT, HuffmanCode HC,int length);//保存权重 
Status Encoding(HuffmanTree &HT,HuffmanCode &HC,int length);//编码 
Status read(char *alpha,int *frequent,int length);//读取字符及其权重 
Status Decoding(HuffmanTree HT,HuffmanCode HC,int length);//解码 
Status Print();//印码
Status writeTree(HuffmanTree HT,unsigned root,int level,FILE *fs);//画树子函数 
Status PrintTree(HuffmanTree HT,unsigned root,int level);//画树 

int main()
{
	/*定义变量,一定放在while外面*/ 
	char userchoice;
	int judge,length,result;
	char *alpha;
	int *frequent;
	HuffmanTree HT=NULL;
	HuffmanCode HC=NULL;
	while(1)
	{
		onScreen ();
		cin>>userchoice;
		while(userchoice!='I'&&userchoice!='E'&&userchoice!='D'&&userchoice!='P'&&userchoice!='T'&&userchoice!='Q')
		{
			cout<<"数据不合要求,请重新输入"<<endl;
			cin>>userchoice; 
		}
		switch(userchoice)
		{
			case 'I':
			    //system("cls");
				cout<<"1.从文档读入字符和频度"<<endl;
				cout<<"2.终端输入字符和频度"<<endl;
				cin>>judge;
				if(judge==1)
				{
					length=27;
					alpha=(char*)malloc(length*sizeof(char));
					frequent=(int*)malloc(length*sizeof(int));
					read(alpha,frequent,length);
				    result=HuffmanCoding(HT, HC, alpha,frequent, length);
				    if(result==OK)
				    {
				    	cout<<endl;
				    	cout<<"字符\t频度\n";
						for(int i=0;i<length;i++)
						{
							cout<<alpha[i]<<"\t";
							cout<<frequent[i]<<"\n";
						}
						cout<<"\n建树操作成功"<<endl;
					}
					else
					cout<<"\n建树操作失败"<<endl;
				}
				else if(judge==2)
				{
					system("cls");
					cout<<"请输入字符的数量:"<<endl;
					cin>>length;
					while(length<=0) 
					{
						cout<<"数据不合要求,请重新输入"<<endl;
						cin>>length; 
					}
					alpha=(char*)malloc(length*sizeof(char));
					frequent=(int*)malloc(length*sizeof(int));
					for(int i=0;i<length;i++)
					{
						cout<<"第"<<i+1<<"个字符是:"<<endl;
						cin>>alpha[i];
						cout<<"它的权重是:"<<endl;
						cin>>frequent[i];
						while(frequent[i]<=0) 
						{
							cout<<"数据不合要求,请重新输入"<<endl;
							cin>>frequent[i]; 
						}
					}
					result=HuffmanCoding(HT, HC, alpha,frequent, length);
				    if(result==OK)
				    {
				    	cout<<endl;
				    	cout<<"字符\t频度\n";
						for(int i=0;i<length;i++)
						{
							cout<<alpha[i]<<"\t";
							cout<<frequent[i]<<"\n";
						}
						cout<<"\n建树操作成功"<<endl;
					}
					else
					cout<<"\n建树操作失败"<<endl;
				}
				break; 
			case 'E':
				//system("cls");
				if(HC&&HT)
				{
					result=Encoding(HT,HC,length);
					if(result==OK) cout<<"\n编码成功"<<endl;
					else cout<<"\n编码失败"<<endl;
				}
				else//哈夫曼树未建立 
				{
					cout<<"哈夫曼树未建立,从文件中读入哈夫曼树"<<endl; 
					length=27;
					alpha=(char*)malloc(length*sizeof(char));
					frequent=(int*)malloc(length*sizeof(int));
					read(alpha,frequent,length);
				    result=HuffmanCoding(HT, HC, alpha,frequent, length);;
				    if(result==OK)
					{
				    	cout<<endl;
				    	cout<<"字符\t频度\n";
						for(int i=0;i<length;i++)
						{
							cout<<alpha[i]<<"\t";
							cout<<frequent[i]<<"\n";
						}
				    cout<<"\n建树操作成功"<<endl;
					}
					else
					cout<<"\n建树操作失败"<<endl;
					result=Encoding(HT,HC,length);
					if(result==OK) cout<<"\n哈夫曼树未建立,从文件中读入哈夫曼树,编码成功\n"<<endl;
					else cout<<"\n编码失败"<<endl;
				}
				break;
			case'D':
			//	system("cls");
				if(HT&&HC)
				{
					result=Decoding(HT,HC,length);
					if(result==OK) cout<<"\n解码成功"<<endl;
					else cout<<"\n解码失败"<<endl;
				}
				else//哈夫曼树未建立 
				{
					cout<<"哈夫曼树未建立,从文件中读入哈夫曼树"<<endl; 
					length=27;
					alpha=(char*)malloc(length*sizeof(char));
					frequent=(int*)malloc(length*sizeof(int));
					read(alpha,frequent,length);
				    result=HuffmanCoding(HT, HC, alpha,frequent, length);;
				    if(result==OK)
					{
				    	cout<<endl;
				    	cout<<"字符\t频度\n";
						for(int i=0;i<length;i++)
						{
							cout<<alpha[i]<<"\t";
							cout<<frequent[i]<<"\n";
						}
				    cout<<"\n建树操作成功"<<endl;
					}
					else
					cout<<"\n建树操作失败"<<endl;
					result=Decoding(HT,HC,length);
					if(result==OK) cout<<"\n哈夫曼树未建立,从文件中读入哈夫曼树,解码成功\n"<<endl;
					else cout<<"\n解码失败"<<endl;
				}
				break; 
			case'P':
				//system("cls");
				result=Print();
				if(result==OK) cout<<"\n印代码文件成功"<<endl;
				else cout<<"\n印代码文件失败"<<endl;
				break; 
			case'T':
			//	system("cls");
				if(!HT) 
				{
					cout<<"树不存在"<<endl;
					break;
				}
				result=PrintTree(HT,GetHuffmanRoot(HT),0);
				if(result==OK) cout<<"\n画树成功"<<endl;
				else cout<<"\n画树失败"<<endl;
				break;
			case'Q':
			    cout<<"感谢使用!"<<endl; 
				return 0; 
		}	
	}
	system("pause"); 
	return 0;
}

void onScreen()
{
	cout<<"-------------------------欢迎使用哈夫曼编译器----------------------------------"<<endl;
	cout<<"请选择需要进行的操作(输入相应字母):"<<endl;
	cout<<"I.初始化并建立哈夫曼树"<<endl;
	cout<<"E.利用哈夫曼树编码"<<endl;
	cout<<"D.利用哈夫曼树译码"<<endl;
	cout<<"P.印制代码文件"<<endl;
	cout<<"T.印制哈夫曼树"<<endl;
	cout<<"Q.退出程序"<<endl;
}

Status read(char *alpha,int *frequent,int length)
{
	FILE *fp;
	char temp[50];
	if((fp=fopen("hfmTree.txt","r"))==NULL)
		cout<<"不能打开文件"<<endl;
	else
	{
		cout<<"打开文件hfmTree.txt成功"<<endl;
		int i=0;
		while((fscanf(fp,"%c\t%d\t%s\n", &alpha[i],&frequent[i],temp))!=EOF)
		{
			i++;
			if(i>=length) break;
		}
		fclose(fp);
		cout<<"读入字符和频率成功"<<endl;
	} 
}

void Select(HuffmanTree HT, int end, int *s1, int *s2)
{
	int min1, min2;//遍历数组初始下标为 1
	int i = 1;//找到还没构建树的结点
	while(HT[i].parent != 0 && i <= end) i++;
	min1 = HT[i].weight;
	*s1 = i;
	i++;
	while(HT[i].parent != 0 && i <= end)i++;
	//对找到的两个结点比较大小,min2为大的,min1为小的
	if(HT[i].weight < min1)
	{
        min2 = min1;
        *s2 = *s1;
        min1 = HT[i].weight;
        *s1 = i;
    }
	else
	{
        min2 = HT[i].weight;
        *s2 = i;
    }
    //两个结点和后续的所有未构建成树的结点做比较
    for(int j=i+1; j <= end; j++)
    {
        //如果有父结点,直接跳过,进行下一个
        if(HT[j].parent != 0){
            continue;
        }
        //如果比最小的还小,将min2=min1,min1赋值新的结点的下标
        if(HT[j].weight < min1){
            min2 = min1;
            min1 = HT[j].weight;
            *s2 = *s1;
            *s1 = j;
        }
        //如果介于两者之间,min2赋值为新的结点的位置下标
        else if(HT[j].weight >= min1 && HT[j].weight < min2){
            min2 = HT[j].weight;
            *s2 = j;
        }
    }
}

Status HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, char* alpha,int *w, int n) 
{
	// 算法6.12
	// w存放n个字符的权值(均>0),构造哈夫曼树HT,
	// 并求出n个字符的哈夫曼编码HC
	int i, j, m, s1, s2, start;
	char *cd;
	unsigned int c, f;
	if (n<=1) return ERROR;
	m = 2 * n - 1;
	HT = (HuffmanTree)malloc((m+1) * sizeof(HTNode));  // 0号单元未用
	for (i=1; i<=n; i++) 
	{ //初始化
		HT[i].weight=w[i-1];
		HT[i].parent=0;
		HT[i].lchild=0;
		HT[i].rchild=0;
		HT[i].alpha=alpha[i-1];
		HT[i].number=i;
	}
	for (i=n+1; i<=m; i++) 
	{ //初始化
		HT[i].weight=0;
		HT[i].parent=0;
		HT[i].lchild=0;
		HT[i].rchild=0;
		HT[i].alpha='#';
		HT[i].number=i;
	}
	printf("\n哈夫曼树的构造过程如下所示:\n");
	printf("HT初态:\n  结点  alpha   weight  parent  lchild  rchild");
	for (i=1; i<=m; i++)
	printf("\n%4d%8c%8d%8d%8d%8d",i,HT[i].alpha,HT[i].weight,
	        HT[i].parent,HT[i].lchild, HT[i].rchild);
	//  printf("    按任意键,继续 ...");
	//  getchar();
	printf("\nHT初态:\n  结点  alpha   weight  parent  lchild  rchild");
	for (i=n+1; i<=m; i++) 
	{  // 建哈夫曼树
	// 在HT[1..i-1]中选择parent为0且weight最小的两个结点,
	// 其序号分别为s1和s2。
		Select(HT, i-1, &s1, &s2);
		HT[s1].parent = i;  HT[s2].parent = i;
		HT[i].lchild = s1;  HT[i].rchild = s2;
		HT[i].weight = HT[s1].weight + HT[s2].weight;
		printf("\n\tselect: s1=%d   s2=%d\n", s1, s2);
		printf("  结点  alpha   weight  parent  lchild  rchild");
		for (j=1; j<=i; j++)
		  printf("\n%4d%8c%8d%8d%8d%8d",j,HT[j].alpha,HT[j].weight,
		         HT[j].parent,HT[j].lchild, HT[j].rchild);
	//printf("    按任意键,继续 ...");
	//  getchar();
	}
	/**/ 
	//--- 从叶子到根逆向求每个字符的哈夫曼编码 ---
	cd = (char *)malloc(n*sizeof(char));    // 分配求编码的工作空间
	cd[n-1] = '\0';                         // 编码结束符。
	HC=(char**)malloc(n*sizeof(char*));
	for(i=1;i<=n;i++) HC[i] = (char *)malloc((n-start)*sizeof(char)); 	// 为第i个字符编码分配空间
	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].lchild==c) 
		    {
		    	start=start-1;
				cd[start] = '0';
			}
		    else 
		    {
		    	start=start-1;
		    	//printf("\n%d",start);
		    	cd[start] = '1';
			}
		}
		strcpy(HC[i], &cd[start]);    // 从cd复制编码(串)到HC
	//	printf("\n%s",&cd[start]);
		// cout<<cd<<endl;
	}
	free(cd);   // 释放工作空间
	return OK;
} // HuffmanCoding

Status saveTreeFrequent(HuffmanTree HT, HuffmanCode HC,int length)
{
	FILE *fp;
	if((fp=fopen("hfmTree.txt","w+"))==NULL)
	{
		cout<<"不能打开文件"<<endl;
		return ERROR;
	}
	else
	{
		cout<<"打开文件hfmTree.txt成功" <<endl;
		for(int i=1;i<=length;i++)
		fprintf(fp,"%c\t%d\t%s\n", HT[i].alpha,HT[i].weight,HC[i]);
	}
	fclose(fp);
	cout<<"保存哈夫曼树成功!"<<endl;
	return OK;	
}

Status Encoding(HuffmanTree &HT,HuffmanCode &HC,int length)
{
	FILE *fp,*fs;
	if(!HC)
	{
		int n=length;
		HC=(char**)malloc(n*sizeof(char*));
		int i;
	    for(i=1;i<=n;i++) 
		{
			HC[i] = (char *)malloc(10*sizeof(char)); 
		}
		if((fp=fopen("hfmTree.txt","r"))==NULL)
		{
			cout<<"不能打开文件hfmTree.txt"<<endl;
			return ERROR;
		}
		else
		{
			cout<<"打开文件hfmTree.txt成功"<<endl; 
			int i=0;
			while((fscanf(fp,"%c\t%d\t%s\n", &HT[i].alpha,&HT[i].weight,HC[i]))!=EOF) 
			{
				i++;
				if(i==length) break;
			}
			fclose(fp);
			cout<<"读入哈夫曼树成功!"<<endl;
		} 	
	}
//	for(int j=1;j<=length;j++) cout<<HC[j]<<endl;
	//准备好编码
	if((fp=fopen("ToBeTran.txt","r"))==NULL)
	{
		cout<<"不能打开文件ToBeTran.txt"<<endl;
		return ERROR;
	} 
	else
	{
		char temp;
		if((fs=fopen("CodeFile.txt","w+"))==NULL)
		{
			cout<<"不能打开文件"<<endl;
			return ERROR;	
		}
		cout<<"打开文件ToBeTran.txt和成功"<<endl;
		cout<<"编码信息已存入CodeFile.txt,内容如下:\n"<<endl; 
		while(fscanf(fp,"%c",&temp)!=EOF)
		{
			if((temp>'Z'||temp<'A')&&(temp!=' '))
			{
				cout<<"\n\n出现不支持字符,编码中断"<<endl;
				return ERROR;
			}
			if(temp==' ')
			{
				fprintf(fs,"%s ", HC[1]);
				printf("%s ", HC[1]);
			}
			
			else
			{
				int number=temp-'A'+2;
				fprintf(fs,"%s ", HC[number]);
				printf("%s ", HC[number]);
			}	
		}
		fclose(fp);
		fclose(fs);
		cout<<endl;
	}
	return OK;
}

int GetHuffmanRoot(HuffmanTree HT)
{
	int i;
	for( i=1;;i++)
	     if(HT[i].parent==0)
	         break;
	return i;
}

Status Decoding(HuffmanTree HT,HuffmanCode HC,int length)
{
	FILE *fp,*fs;
	char tempCode[20];
	char tempAlpha;
	if((fp=fopen("CodeFile.txt","r"))==NULL)
	{
		cout<<"不能打开文件CodeFile.txt"<<endl;
		return ERROR;
	}
	else
	{
		if((fs=fopen("TextFile.txt","w+"))==NULL)
		{
			cout<<"不能打开文件TextFile.txt"<<endl;
			return ERROR;
		}
		int Alphaposition;
		cout<<"打开文件CodeFile.txt和TextFile.txt成功"<<endl;
		cout<<"解码信息已存入TextFile.txt中,内容如下\n"<<endl; 
		while((fscanf(fp,"%s",tempCode))!=EOF)
		{
			
			unsigned int Alphaposition=GetHuffmanRoot(HT);
			for(int i=0,j=1;i<strlen(tempCode);i++)
			{
				if(tempCode[i]=='0')
				Alphaposition=HT[Alphaposition].lchild;
				else if(tempCode[i]=='1')
				Alphaposition=HT[Alphaposition].rchild;
				else 
				{
					cout<<"\n\n出现错误信息,解码中断\n";
					return ERROR;
				}	
			}
			tempAlpha=HT[Alphaposition].alpha;
			fprintf(fs,"%c",tempAlpha);
			printf("%c",tempAlpha); 
		}
		cout<<endl;
		fclose(fp);
		fclose(fs);//关闭文件至关重要,不然下次再弄就出bug 
	} 
	return OK; 
}

Status Print()
{
	FILE *fp,*fs;
	char tempCode[20];
	char tempAlpha;
	if((fp=fopen("CodeFile.txt","r"))==NULL)
	{
		cout<<"不能打开文件CodeFile.txt"<<endl;
		return ERROR;
	}
	else
	{
		if((fs=fopen("CodePrin.txt","w+"))==NULL)
		{
			cout<<"不能打开文件CodePrin.txt"<<endl;
			return ERROR;
		}
		cout<<"打开文件CodeFile.txt和CodePrin.txt成功"<<endl;
		cout<<"编码信息已存入CodePrin.txt中,内容如下:\n"<<endl;
		int Alphaposition;
		int count=0;
		while((fscanf(fp,"%s",tempCode))!=EOF)
		{
			count+=strlen(tempCode);
			if(count>=50) 
			{
				printf("\n");
				fprintf(fs,"\n");
				count=0; 
			}
			printf("%s ",tempCode);
			fprintf(fs,"%s ",tempCode);
		}
		cout<<endl;
		fclose(fp);
		fclose(fs);//关闭文件至关重要,不然下次再弄就出bug 
		cout<<"\n写入CodePrin.txt成功";
	} 
	return OK; 
}

Status writeTree(HuffmanTree HT,unsigned root,int level,FILE *fs)
{
	if(!HT) return ERROR;
	for(int i=1;i<level;i++)
	{
		printf("\t");
		fprintf(fs,"\t");
	}
	fprintf(fs,"%c%d\n",HT[root].alpha,HT[root].number);
	printf("%c%d\n",HT[root].alpha,HT[root].number);
	if(root>27)
	{
	    writeTree(HT,HT[root].rchild, level+1,fs);
		writeTree(HT,HT[root].lchild, level+1,fs);
	}
	return OK;
}

Status PrintTree(HuffmanTree HT,unsigned root,int level)
{
    if(!HT) return ERROR;
	FILE *fs;
	if((fs=fopen("TreePrint.txt","w+"))==NULL)
	{
		cout<<"不能打开文件TreePrint.txt"<<endl;
		return ERROR;
	}
	cout<<"打开文件TreePrint.txt成功"<<endl; 
	writeTree(HT,root,level,fs);
	fclose(fs);
	return OK;
}

设计和调试分析

  1. 在调试HuffmanCoding函数时发现总是不能正确输出后十个字母相应的编码,耗费了大量时间,最终发现是malloc出现了问题。由于HC相当于二维数组,需要两次malloc,分别是
HC=(char**)malloc(n*sizeof(char*))

for(i=1;i<=n;i++) HC[i] = (char *)malloc((n-start)*sizeof(char))

但在最初漏掉了第一条语句,即使编译器不报错,HC所使用的空间也是非法的,自然导致了后续输出的问题。

  1. 在进行保存等文件操作时,最初经常出现保存失败的情况。经过检查发现是漏掉了fclose()函数,在以后写代码的过程中,应牢记文件的打开与关闭操作必须成对出现。
  2. 本算法的时间主要消耗在从结点中选择权值最小的两棵树根结点上,每构建一个非叶子结点都需要比较(i-1)次,构建n-1个非叶子结点总比较次数达到(3n-2)(n-1)/2,因此算法的时间复杂度为O(n2),空间复杂度为O(1)。

用户手册

  1. 本程序的运行环境为windows10操作系统,执行文件为:哈夫曼树.exe;
  2. 打开后显示文本方式的用户界面:
    -------------------------欢迎使用哈夫曼编译器--------------
    请选择需要进行的操作(输入相应字母):
    I.初始化并建立哈夫曼树
    E.利用哈夫曼树编码
    D.利用哈夫曼树译码
    P.印制代码文件
    T.印制哈夫曼树
    Q.退出程序
    3. 输入I,初始化并建立哈夫曼树;输入E,利用哈夫曼树编码,如果哈夫曼树不存在,则可调用I;输入D,利用哈夫曼树译码。如果哈夫曼树不存在,则可调用I;输入P,印制代码文件;输入T,印制哈夫曼树;输入Q,退出程序。

测试结果

  1. 输入I,初始化并建立哈夫曼树

字符    频度
        186    (此处为空格的=字符及其频度)
A       64
B       12
C       22
D       32
E       103
F       21
G       15
H       47
I       57
J       1
K       5
L       32
M       20
N       57
O       63
P       15
Q       1
R       48
S       51
T       80
U       23
V       8
W       18
X       1
Y       16
Z       1
  1. 输入E,编码ToBeTran.txt中的文件,并将编码信息存入CodeFile.txt中,此时ToBeTran.txt中的内容为:
THIS IS MY FAVORITE PROGRAM

终端输出:文章来源地址https://www.toymoban.com/news/detail-421258.html

打开文件ToBeTran.txt和成功
编码信息已存入CodeFile.txt,内容如下:
1101 0001 0110 0011 111 0110 0011 111 110010 100011 111 110011 1010 1100000 1001 0010 0110 1101 010 111 100010 0010 1001 100001 0010 1010 110010
编码成功
  1. 输入D,将CodeFile.txt中的编码解码并保存到TextFile.txt中,终端输出为:
打开文件CodeFile.txt和TextFile.txt成功
解码信息已存入TextFile.txt中,内容如下
THIS IS MY FAVORITE PROGRAM
解码成功
  1. 输入P,将CodeFile.txt中的内容存入CodePrin.txt中,终端输出为:
打开文件CodeFile.txt和CodePrin.txt成功
编码信息已存入CodePrin.txt中,内容如下:
1101 0001 0110 0011 111 0110 0011 111 110010 100011 111
110011 1010 1100000 1001 0010 0110 1101 010 111 100010 0010 1001100001 0010 1010 110010
写入CodePrin.txt成功
印代码文件成功

到了这里,关于【数据结构实验】哈夫曼树的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构“基于哈夫曼树的数据压缩算法”的实验报告

    一个不知名大学生,江湖人称菜狗 original author: jacky Li Email : 3435673055@qq.com Last edited: 2022.11.20 目录 数据结构“基于哈夫曼树的数据压缩算法”的实验报告 一、实验目的 二、实验设备 三、实验内容 1.【问题描述】 2.【输入要求】 3.【输出要求】 4.【实验提示】 四、实验步骤

    2024年02月09日
    浏览(61)
  • 数据结构 实验17:Huffman树和Huffman编码——学习理解哈夫曼树

    目录 前言 实验要求 算法描述 个人想法 代码实现和思路、知识点讲解 知识点讲解 文件传输 Huffman树的存储 Huffman的构造  Huffman编码 编码和译码 代码实现 文件写入和输出 Huffman树初始化 构造Huffman树 求带权路径长度 Huffman编码 Huffman译码 结束 代码测试 测试结果 利用Huffman编

    2024年02月03日
    浏览(61)
  • 数据结构——哈夫曼树与哈夫曼编码

    1.1 基本概念 路径 :指从根结点到该结点的分支序列。 路径长度 :指根结点到该结点所经过的分支数目。 结点的带权路径长度 :从树根到某一结点的路径长度与该结点的权的乘积。 树的带权路径长度(WPL) :树中从根到所有叶子结点的各个带权路径长度之和。 哈夫曼树 是由

    2024年02月05日
    浏览(46)
  • 数据结构之哈夫曼树和哈夫曼编码

    切入正题之前,我们先了解几个概念: 路径:从树的一个结点到另一个结点分支所构成的路线 路径长度:路径上的分支数目 树的路径长度:从根结点出发到每个结点的路径长度之和 带权路径长度:该结点到根结点的路径长度乘以该结点的权值 树的带权路径长度:树中所有

    2024年02月11日
    浏览(45)
  • 数据结构之哈夫曼树与哈夫曼编码

    编码是信息处理的基础(重新表示信息)。 普通的编码是等长编码,例如7位的ASCIL编码,对出现频率不同的字符都使用相同的编码长度。 但其在传输和存储等情况下编码效率不高 。 可使用不等长编码,来压缩编码:高频字符编码长度更短,低频字符编码长度更长。   [例

    2023年04月15日
    浏览(64)
  • 【数据结构与算法】-哈夫曼树(Huffman Tree)与哈夫曼编码

    超详细讲解哈夫曼树(Huffman Tree)以及哈夫曼编码的构造原理、方法,并用代码实现。 路径 :从树中一个结点到另一个结点之间的 分支 构成这两个结点间的路径。 结点的路径长度 :两结点间路径上的 分支数 。 树的路径长度: 从树根到每一个结点的路径长度之和。记作: TL  权

    2024年02月06日
    浏览(53)
  • 数据结构-哈夫曼树

    介绍 哈夫曼树,指 带权路径长度最短的二叉树 ,通常用于数据压缩中 什么是带权路径长度? 假设有一个结点,我们为它赋值,这个值我们称为权值,那么从根结点到它所在位置,所经历的路径,与这个权值的积,就是它的带权路径长度。 比如有这样一棵树,D权值为2  从

    2024年02月20日
    浏览(44)
  • 数据结构----哈夫曼树

    哈夫曼树就是寻找构造最优二叉树,用于提高效率 各种路径长度 各种带权路径长度 结点的带权路径长度 树的带权路径长度 哈夫曼树 带权路径长度最短的树或者二叉树 也就是树的叶子结点带权路径长度之和 :也就是叶子结点的结点路径长度(根结点到叶子结点的路径数)

    2024年01月21日
    浏览(49)
  • 数据结构【哈夫曼树】

    最优二叉树也称哈夫曼 (Huffman) 树 ,是指对于一组带有确定权值的叶子结点,构造的具有最小带权路径长度的二叉树。权值是指一个与特定结点相关的数值。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。 涉及到的几个概念: 路径: 从树中一个结点到另一个结

    2024年02月14日
    浏览(40)
  • 【数据结构-树】哈夫曼树

    💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学习,不断总结,共同进步,活到老学到老 导航 檀越剑指大厂系列:全面总

    2024年02月08日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包