【数据结构 】哈夫曼编译码器

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

题目

题目描述

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

基本要求

  • 基本要求
    系统应具有以下功能:
    ① I:初始化.从终端读入字符集大小n及n个字符和n个权值,建立哈夫曼树,井将它存于文件HuffmanTree中。
    ② C:编码。利用已建立好的哈夫曼树(如不在内存,则从文件HuffmanTree中读入)。对文件tobetrans中的正文进行编码,然后将结果存入文件codefile中。
    ③ D:解码。利用已建立好的哈夫曼树将文件codefile中的代码进行译码,结果存入testfile中。
    ④ P:打印代码文件。将文件codefile以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件codeprint中。
    ⑤ T:打印哈夫曼树。将已在内存中的哈夫曼树直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件treeprint中。

算法分析

  • 本题例主要用到3个算法如下:
    ① 哈夫曼编码。在初始化(I)的过程中,要用输入的字符和权值建立哈夫曼树并求得哈夫曼编码。先将输入的字符和权值放到一个结构体数据中,建立哈夫曼树,将计算所得的哈夫曼编码存储到另一个结构体数组中。
    ② 串的匹配。在解码(D)的过程中,要对已经编码过的代码进行译码,可利用循环,将代码中与哈夫曼编码长度相同的串与这个哈夫曼编码进行比较,如果相等就回显并存入文件。
    ③二叉树的遍历。在打印哈夫曼树(T)的过程中,因为哈夫曼树也是二叉树,所以就要利用二叉树的前序遍历将哈夫曼树输出。

代码实现

代码部分参考了《数据结构-C语言版第2版》这本书中代码以及C++风格进行书写,测试文件tobetrans中的内容为"ABCABC"

初始化

题目要求从终端读入字符集大小n及n个字符和n个权值,建立哈夫曼树,并将它存于文件HuffmanTree中,可以先将哈夫曼树构建起来,得到哈夫曼树及其对应叶子节点的编码,再通过文件的输入输出将这些编码写入文件HuffmanTree中即可

  • 构造哈夫曼树
/*找出森林集合中根权值最小的两个*/
void Select(HuffmanTree HT,int len,int &s1,int &s2)
{
	int i,min1=0x3f3f3f3f,min2=0x3f3f3f3f;//先赋予最大值
	for(i=1;i<=len;i++)
	{
		if(HT[i].weight<min1&&HT[i].parent==0)
		{
			min1=HT[i].weight;
			s1=i;
		}	
	}
	int temp=HT[s1].weight;//将原值存放起来,然后先赋予最大值,防止s1被重复选择
	HT[s1].weight=0x3f3f3f3f;
	for(i=1;i<=len;i++)
	{
		if(HT[i].weight<min2&&HT[i].parent==0)
		{
			min2=HT[i].weight;
			s2=i;
		}
	}
	HT[s1].weight=temp;//恢复原来的值
}

/*构建哈夫曼树*/
void CreatHuffmanTree(HuffmanTree &HT,int n)
{
	//构造赫夫曼树HT
	int m,s1,s2,i;
	if(n<=1) return;
	m=2*n-1;
	HT=new HTNode[m+1];  		//0号单元未用,所以需要动态分配m+1个单元,HT[m]表示根结点   
	for(i=1;i<=m;++i)        	//将1~m号单元中的双亲、左孩子,右孩子的下标都初始化为0   
	   { HT[i].parent=0;  HT[i].lchild=0;  HT[i].rchild=0; }
	cout<<"请输入叶子结点的字符和权值:\n";
	for(i=1;i<=n;++i)        	//输入前n个单元中叶子结点的权值  
		cin>>HT[i].s>>HT[i].weight;  
	/*――――――――――初始化工作结束,下面开始创建赫夫曼树――――――――――*/ 
	for(i=n+1;i<=m;++i) 
	{  	//通过n-1次的选择、删除、合并来创建赫夫曼树
		Select(HT,i-1,s1,s2);
		//在HT[k](1≤k≤i-1)中选择两个其双亲域为0且权值最小的结点,
		// 并返回它们在HT中的序号s1和s2
		HT[s1].parent=i; 	
		HT[s2].parent=i;   
		//得到新结点i,从森林中删除s1,s2,将s1和s2的双亲域由0改为i
		HT[i].lchild=s1;   
		HT[i].rchild=s2;							//s1,s2分别作为i的左右孩子
		HT[i].weight=HT[s1].weight+HT[s2].weight; 	//i 的权值为左右孩子权值之和
	}											
}
  • 哈夫曼编码
/*哈夫曼树编码*/
void CreatHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n)
{
	//从叶子到根逆向求每个字符的赫夫曼编码,存储在编码表HC中
	int i,start,c,f;
	HC=new char*[n+1];         						//分配n个字符编码的头指针矢量
	char *cd=new char[n];							//分配临时存放编码的动态数组空间
	cd[n-1]='\0';                            		//编码结束符
	for(i=1;i<=n;++i)
	{                      							//逐个字符求赫夫曼编码
		start=n-1;                          		//start开始时指向最后,即编码结束符位置
		c=i; 
		f=HT[i].parent;                 			//f指向结点c的双亲结点
		while(f!=0)
		{                          					//从叶子结点开始向上回溯,直到根结点
			--start;                          		//回溯一次start向前指一个位置
			if(HT[f].lchild==c)  
				cd[start]='0';						//结点c是f的左孩子,则生成代码0
			else 
				cd[start]='1';                 		//结点c是f的右孩子,则生成代码1
			c=f; 
			f=HT[f].parent;             			//继续向上回溯
		}                                  			//求出第i个字符的编码      
		HC[i]=new char[n-start];         			// 为第i 个字符编码分配空间
		strcpy(HC[i], &cd[start]);        			//将求得的编码从临时空间cd复制到HC的当前行中
	}
	delete cd;                            			//释放临时空间
}
  • 将编码写入到文件HuffmanTree
    这里通过循环将构造好的哈夫曼编码直接写入到文件
//编码写入文件HuffmanTree.txt
void printCreatHuffmanCode(HuffmanTree HT, HuffmanCode HC,int n)
{
    ofstream hFile("HuffmanTree.txt");
    if (!hFile.is_open()) {
        cout << "文件HuffmanTree.txt打开失败." << endl;
        exit(1);
    } 
	cout<<"各字符对应的编码如下:"<<endl; 
    for (int i = 1; i <=n; i++)
    {
        cout << HT[i].s << HC[i] << endl;
        hFile << HT[i].s << HC[i]<<endl; 
    }

	hFile.close();
    cout << "成功写入文件HuffmanTree.txt" << endl;
}

初始化部分运行截图如下:
【数据结构 】哈夫曼编译码器,数据结构,数据结构,算法

编码

思路:通过文件逐行读出字符,并将其存放到数组,通过遍历该数组以及哈夫曼树,从而将对应的编码写入到文件codefile.txt中

//编码部分 
void Huffmancode(HuffmanTree HT,HuffmanCode HC,int n) {
    // 函数用于对 "tobetrans.txt" 文件中的内容进行编码,并将结果存储在 "codefile.txt" 文件中
    // 假设 "tobetrans.txt" 包含要编码的内容,每一行表示一个要编码的字符串。
	ifstream tFile("tobetrans.txt");//读 
	ofstream cFile("codefile.txt");//写 
	
	if (!tFile.is_open()) {
	    cout << "文件tobetrans.txt打开失败.\n"<<endl;
	    exit(1);
	}
	if (!cFile.is_open()) {
	    cout << "文件codefile.txt打开失败.\n"<<endl;
	    exit(1);
	}
	
	char tobetrans[100];//临时存放文件中每一行的字符 
	
	// 逐行读取内容
	while (tFile.getline(tobetrans, sizeof(tobetrans))) {//行不空 
	   
	    int m= strlen(tobetrans);//数组长度,即每一行字符个数
		cout<<"tobetrans内容:"<<tobetrans; 
		cout<<endl; 
	    for (int i = 0; i <m; i++) {//遍历数组 
	    	for(int j=1;j<=n;j++) //遍历树节点(0号单元为根节点未启用) 
	    	{
	    		if (HT[j].s == tobetrans[i]) {//相等则将其对应的编码写入文件 
	        	cFile << HC[j];
				}
	        }
	    }
	}
	 
	tFile.close();
	cFile.close();
	cout<<"成功写入文件codefile.txt"<<endl;

}

编码部分运行截图如下:
【数据结构 】哈夫曼编译码器,数据结构,数据结构,算法

解码

思路:和编码部分一样,先从文件逐行读出存入数组,接着再遍历该数组和树的节点,从而将对应的字符写入到testfile.txt中

//译码部分 
void HuffmanDecode(HuffmanTree HT, int n) {
	//函数用于利用已建立好的哈夫曼树将文件"codefile.txt"中的代码进行译码,结果存入"testfile.txt"中

	ifstream codeFile("codefile.txt");//读 
	ofstream testFile("testfile.txt");//写 
	
	if (!codeFile.is_open()) {
	    cout << "文件codefile.txt打开失败.\n"<<endl;
	    exit(1);
	}
	if (!testFile.is_open()) {
	    cout << "文件testfile.txt打开失败.\n"<<endl;
	    exit(1);
	}
	
	char pwd[100];
	codeFile.getline(pwd, sizeof(pwd));//每次读取一行放入数组pwd中进行译码 
	
	int len = strlen(pwd);
	int i = 0;
	int node = 2 * n - 1;//从根节点开始 
	
    while (i < len) {  // 循环遍历读取数组中的每个字符
        while (HT[node].lchild != 0 && HT[node].rchild != 0) {  // 当当前节点不是叶子节点时循环
            if (pwd[i] == '0') {  // 如果当前读取的字符是 '0'
                node = HT[node].lchild;  // 移动到当前节点的左孩子节点
            } else if (pwd[i] == '1') {  // 如果当前读取的字符是 '1'
                node = HT[node].rchild;  // 移动到当前节点的右孩子节点
            }
            i++;  // 移动到下一个字符
        }
        testFile << HT[node].s;  // 将叶子节点对应的字符写入到输出文件中
        node = 2 * n - 1;  // 将节点移动回到根节点
    }

	
	codeFile.close();
	testFile.close();
	cout << "成功写入文件testfile.txt" << endl;

}

解码部分运行截图如下:
【数据结构 】哈夫曼编译码器,数据结构,数据结构,算法

打印代码

思路:通过文件逐行读出二进制码,在根据题目要求将对应的格式输出到终端输入到文件(我这里以每5行为例)

//打印代码文件 
void Print()
{
	//函数用于将文件codefile.txt以紧凑格式显示在终端上,每行5个代码。
	//同时将此字符形式的编码文件写入文件codeprint.txt中。 
	char str[1000];//存储codefile.txt的0-1编码 
	int num = 0;
	ifstream file1("codefile.txt");//读出 
	ofstream file2("codeprint.txt");//写入 
	if(file1.fail()){
		cout<<"文件codefile.txt打开失败"<<endl;
		exit(0);
	}
	if(file2.fail()){
		cout<<"文件codeprint.txt打开失败"<<endl;
		exit(0);
	}
	file1.getline(str, 10000);//读取每一行
	cout<<"str内容"<<str; 
	cout<<endl;
	cout<<"文件codefile.txt内容显示如下:"<<endl; 
	while(str[num]){
		if(num%5==0&&num!=0)//每输出5个字符换行,由于数组下标从0开始所以要忽略num==0这个情况 
		{
			cout<<endl; 
			file2<<endl;//文件里也是每5个字符换行 
		}
		cout<<str[num];
		file2<<str[num];//写入文件 
		num++; 				
	}
	cout<<endl;
	file1.close();
	file2.close();
	cout<<"成功写入文件codeprint.txt"<<endl;	
	
}

打印代码部分运行截图如下:
【数据结构 】哈夫曼编译码器,数据结构,数据结构,算法

打印哈夫曼树

这里结合树的前序遍历,并以凹入表的形式进行输出

void PrintHuffmanTree(HuffmanTree HT, int root, int level) {
    // 递归打印哈夫曼树的结构(凹入表形式)
    if (root != 0) {
        // 打开文件 treeprint.txt
        ofstream treeFile("treeprint.txt", ios::app);  // 使用 ios::app 追加模式
        if (treeFile.fail()) {
            cout << "文件 treeprint.txt 打开失败" << endl;
            exit(0);
        }

        // 输出当前节点信息(以凹入表形式)
        cout << string(4 * level, ' ');  // 控制缩进
        cout << HT[root].weight;//输出节点权值 
        if (HT[root].s) {
            cout << " (" << HT[root].s << ")";//节点字符 
        }
        cout << endl;
        
        treeFile << string(4 * level, ' ');
        treeFile << HT[root].weight;
        if (HT[root].s) {
            treeFile << " (" << HT[root].s << ")";
        }
        treeFile << endl;

        // 递归打印左右子树
        PrintHuffmanTree(HT, HT[root].lchild, level + 1);
        PrintHuffmanTree(HT, HT[root].rchild, level + 1);
    }
}

打印哈夫曼树运行截图如下:
【数据结构 】哈夫曼编译码器,数据结构,数据结构,算法

总结

关于如何书写一个哈夫曼编译码器,以上代码大家可以参考,仅供参考!!!毕竟我写的也不是很优秀,只能做到题目的要求,代码中还有许多可以优化的地方,介于自己能力有限,就先分享这么多,大家如果在参考以上代码存在问题时,需要我自己书写的完整代码可以私信我哦,在此感谢各位大佬的支持!文章来源地址https://www.toymoban.com/news/detail-801935.html

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

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

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

相关文章

  • 数据结构之哈夫曼树和哈夫曼编码

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

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

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

    2023年04月15日
    浏览(64)
  • 数据结构课程实验五:哈夫曼树与哈夫曼编码

    实验日期:2022-12-20   目录 一、实验目的 1、掌握哈夫曼树的建立 2、掌握哈夫曼编码方式 二、实验内容

    2024年02月05日
    浏览(50)
  • 【数据结构与算法】-哈夫曼树(Huffman Tree)与哈夫曼编码

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

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

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

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

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

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

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

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

    为一个信息收发站编写一个哈夫曼码的编/译码系统。文末贴出了源代码。 完整的系统需要具备完整的功能,包含初始化、编码、译码、印代码文件和印哈夫曼树,因此需要进行相应的文件操作进行配合。 哈夫曼树的字符集和频度可以从文件中读入,也可以让用户手动输入,

    2023年04月22日
    浏览(45)
  • 【数据结构-树】哈夫曼树

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

    2024年02月08日
    浏览(47)
  • 【数据结构】实验十:哈夫曼编码

    实验十 哈夫曼编码 一、实验目的与要求 1 )掌握树、森林与二叉树的转换; 2 )掌握哈夫曼树和哈夫曼编码算法的实现; 二、 实验内容 1.  请编程实现如图所示的树转化为二叉树。 2.  编程实现一个哈夫曼编码系统,系统功能包括: (1)  字符信息统计:读取待编码的源文

    2024年02月15日
    浏览(48)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包