合肥工业大学2021离散数学上机实验八

实验八:最优树Huffman 算法求解

  1. 实验目的和要求

        实验目的:

        Huffman 算法的一个经典应用就是 Huffman 编码,结合在图论部分对二元树这种图结构的学习,了解该算法在数据通信编码、图像压缩编码中的最直接应用。主要描述为:数据通信中经常需要将传送的内容转换成二进制编码,Huffman 编码是一种变长的编码方案,其核心是使频率越高的码采用越短的编码方式,同时所有码在解码时不会出现二义性。

        理解最优二元树的编码原理,并借助 Huffman 算法实现最优树求解。

        实验要求:

        (1).借助已有平台基于 Huffman 算法求解实验最优二元树的求解。

        (2).或自行编码实现最优二元树的求解及结果展示。

      2. 实验环境和工具

        开发环境:Visual Studio 2019

      3. 实验结果

        3.1 程序流程图

                                 

        3.2 程序代码 (仅供参考,水平有限,有错请指出)

#include<iostream>
#include<fstream>
#include<vector>
#include<stack>
#include<algorithm>
#include<string>
#include<unordered_map>
#include<queue>
using namespace std;
class Hnode
{
public:
	Hnode(int w, char a)
	{
		this->weight = w;
		this->data = a;
		this->lchild = NULL;
		this->rchild = NULL;
	}
	Hnode()
	{
		this->weight = 0;
		this->lchild = NULL;
		this->rchild = NULL;
	}
	string code;//哈夫曼编码(string型)
	//int* code;//哈夫曼编码(int型)
	int weight;//权值
	char data;//字符
	Hnode* lchild;//左子树
	Hnode* rchild;//右子树
};
class HuffmanTree
{
public:
	HuffmanTree();//构造函数,读取文件创建与字符数相等的动态数组
	Hnode* get_root();//取根结点
	void Coding(Hnode* p);//编码
	void input();//从文件中读入原文
	void creat();//建树
	void sort(int size);//构建过程中的排序
	Hnode* combine(Hnode* t1, Hnode* t2);//取两个最小权值结点结合
	void Delete(Hnode* insert, int size);//结合后删除列表中那两个被结合的结点
	void read();//读取文件中的原文
	void load_code(Hnode* p);//将字符与对应的编码储存到数组中
	void Print(Hnode* p);//大音哈夫曼树
	void Mid(Hnode* p);//中序遍历哈夫曼树
private:
	int weight[126] = { 0 };
	int num;
	Hnode** w;
	Hnode* root;
	string a[126];//存码表
	vector<Hnode*>v;
};
HuffmanTree::HuffmanTree()
{
	this->read();
	w = new Hnode * [num];
}
Hnode* HuffmanTree::get_root()
{
	return this->root;
}
void HuffmanTree::Mid(Hnode* p)
{
	if (p != NULL)
	{
		Mid(p->lchild);
		v.push_back(p);
		Mid(p->rchild);
	}
}
void HuffmanTree::Print(Hnode* p)
{
	string template_str;//模板string,表示每行打印string的长度
	int location = 0;
	unordered_map<Hnode*, int> first_locations;//存储节点对应在本行string中的首位置
	for (auto& i : v) 
	{
		location = template_str.size();
		template_str +=  to_string(i->weight) + " ";
		first_locations[i] = location;
	}
	for (auto& i : template_str)//把模板全部置为空格方便后续使用
		i = ' ';
	queue<Hnode*> q;//逐层按序遍历
	q.push(p);
	while (!q.empty()) 
	{
		int currentLevelSize = q.size();
		int cur_loc = 0;
		string tmp_str1 = template_str, tmp_str2 = template_str;//1为节点所在行,2为其下一行
		for (int i = 1; i <= currentLevelSize; ++i) 
		{
			Hnode* node = q.front();
			q.pop();
			cur_loc = first_locations[node];
			string num_str =  to_string(node->weight);
			//左边,如果存在左孩子,那么在第二行对应位置打印'/',在第一行补上'_'
			if (node->lchild) 
			{
				q.push(node->lchild);
				int first_loc = first_locations[node->lchild] + 1;
				tmp_str2[first_loc++] = '/';
				while (first_loc < cur_loc)tmp_str1[first_loc++] = '_';
			}
			//中间,对应位置打印节点值(有可能为多位数)
			for (int j = 0; j < num_str.length(); ++j, ++cur_loc) 
			{
				tmp_str1[cur_loc] = num_str[j];
			}
			//右边,如果存在右孩子,那么在第二行对应位置打印'\',在第一行补上'_'
			if (node->rchild) 
			{
				q.push(node->rchild);
				int last_loc = first_locations[node->rchild] - 1;
				tmp_str2[last_loc] = '\\';
				while (cur_loc < last_loc) 
				{
					tmp_str1[cur_loc++] = '_';
				}
			}
		}
		//打印两行
		 cout << tmp_str1 <<endl;
		 cout << tmp_str2 <<endl;
	}
}
void HuffmanTree::load_code(Hnode* p)
{
	if (p != NULL)
	{
		if (p->data != NULL)
		{
			a[int(p->data)] = p->code;
		}
		load_code(p->lchild);
		load_code(p->rchild);
	}
}
void HuffmanTree::read()
{
	ifstream ifs;
	ifs.open("original_test1.txt", ios::in);
	if (!ifs.is_open())
	{
		cout << "文件打开失败" << endl;
		return;
	}
	string file;
	while (!ifs.fail())
	{
		string buf;
		getline(ifs, buf);
		file += buf;
		file += '\n';
	}
	file.pop_back();
	file.pop_back();
	for (int i = 0; i < file.size(); i++)
	{
		weight[int(file[i])]++;
	}
	this->num = 0; int j = 0;
	for (; j < 126; j++)
	{
		if (weight[j] != 0)
		{
			num++;
		}
	}
	ifs.close();
}
void HuffmanTree::input()
{
	int j = 0, k = 0;
	for (; j < 126; j++)
	{
		if (weight[j] != 0)
		{
			w[k] = new Hnode(weight[j], char(j));
			k++;
		}
	}
}
void HuffmanTree::sort(int size)
{
	Hnode* temp = new Hnode;
	for (int i = 0; i < size; i++)
	{
		for (int j = 0; j < size - 1 - i; j++)
		{
			if (w[j]->weight > w[j + 1]->weight)
			{
				temp = w[j];
				w[j] = w[j + 1];
				w[j + 1] = temp;
			}
		}
	}
}
Hnode* HuffmanTree::combine(Hnode* t1, Hnode* t2)
{
	Hnode* temp = new Hnode;
	temp->weight = t1->weight + t2->weight;
	temp->lchild = t1;
	temp->rchild = t2;
	return temp;
}
void HuffmanTree::Delete(Hnode* insert, int size)
{
	w[0] = insert;
	for (int i = 1; i < size - 1; i++)
		w[i] = w[i + 1];
}
void HuffmanTree::creat()
{
	for (int i = 0; i < num - 1; i++)
	{
		sort(num - i);
		root = combine(w[0], w[1]);
		Delete(root, num - i);
	}
}
void HuffmanTree::Coding(Hnode* p)
{
	if (p != NULL)
	{
		if (p->lchild != NULL)
		{
			p->lchild->code = p->code + '0';
		}
		if (p->rchild != NULL)
		{
			p->rchild->code = p->code + '1';
		}
		//if (p->data != '\0')
			cout << "字符:" << p->data << "  权值:" << p->weight << "  编码:" << p->code << endl;
		Coding(p->lchild);
		Coding(p->rchild);
	}
}
int main()
{
	HuffmanTree H;
	H.input();
	H.creat();
	cout << "哈夫曼编码如下:" << endl;
	H.Coding(H.get_root());
	H.load_code(H.get_root());
	H.Mid(H.get_root());
	H.Print(H.get_root());
	return 0;
}

       3.3 运行结果

其他实验:

合肥工业大学2021离散数学上机实验一https://blog.csdn.net/qq_52791068/article/details/122654230

合肥工业大学2021离散数学上机实验四https://blog.csdn.net/qq_52791068/article/details/122656507

合肥工业大学2021离散数学上机实验六https://blog.csdn.net/qq_52791068/article/details/122656801

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值