c++实现哈夫曼编码

#include<iostream>
#include<string>
using namespace std;

//哈夫曼树结构
typedef struct HFnode
{
	int data; //字母权值
	string leter; //对应字母
	HFnode *lson, *rson; //左右子树
	HFnode *next, *parent; //森林域和双亲域
}*HFptr;

//哈夫曼所有结点的字符集合
//用于后面的译码
typedef struct HFaggregate
{
	string leter; //哈夫曼结点的字母值
	HFnode *point; //指向对应哈夫曼结点
}*HFag;

//哈夫曼森林转为哈夫曼树的函数
void mergeHFT(HFptr &root, int size)
{
	//n棵哈夫曼子树合并为一颗哈夫曼树
	HFptr t1, t2, p, q, r;
	for (int i = 0; i < size; i++)
	{
		r = new HFnode();
		t1 = root->next;
		t2 = t1->next;
		t1->parent = t2->parent = r;
		r->lson = t1;
		r->rson = t2;
		r->leter = "0";
		root->next = t2->next;
		p = root;
		q = root->next;
		//将新生点r有序插入森林域中
		while (1)
		{
			if (q->data < r->data)
			{
				p = q;
				q = q->next;
			}
			else
			{
				r->next = r;
				p->next = r;
				break;
			}
		}
	}
	p = root;
	root = root->next;
	delete p;
}

//创建哈夫曼森林的函数
//root——哈夫曼树的根, set——后面译码需要用到的字符集合size数据个数
void createHFT(HFptr &root, HFag &set, int size)
{
	int num = 0;
	string str;
	HFptr p = nullptr;
	//动态创建哈夫曼树与字母集合
	p = root = new HFnode();
	set = new HFaggregate[size];
	//根的权重最大 0x7f7f为16进制的最大数
	root->data = 0x7f7f;
	cout << "请输入相应字符与权重(权重从小到大输入):" << endl;
	//权重从小到大输入,若乱序,则需要进行排序后构造哈夫曼树
	for (int i = 0; i < size; i++)
	{
		p->next = new HFnode();
		p = p->next;
		p->lson = p->rson = p->parent = nullptr;
		cin >> str >> num;
		//分别将str字母与对应的权重num赋值给哈夫曼树字结点 p 与 字母集合 set 中
		//set[i]是set的一个元素  set是集合
		p->leter = set[i].leter = str;
		p->data = num;
		//set同时还存储对应字母的哈夫曼树结点指针
		set[i].point = p;
	}
	p->next = root;
	//调用mergeHFT函数将哈夫曼森林合并成一棵树
	//size-1  例如5个结点,合并次数4次就行了,故合并次数 = 结点 - 1
	mergeHFT(root, size - 1);
}


//哈夫曼树译码
void decoding(HFptr root)
{
	string str, x;
	HFptr p = root;
	cin >> str;
	//对输入译码的字符串str逐个去编码
	for (size_t i = 0; i <= str.size(); i++)
	{
		x = str[i];
		//判断当前字符x是左子树还是右子树
		if (x == "0")
		{
			//当前结点为叶子结点,则打印
			if (p->lson == nullptr)
			{
				cout << p->leter;
				//记得p要重新指向root下次查找还是进行
				p = root;
				//否则就找当前结点的左子树
				p = p->lson;
			}
		}
		else
		{
			//当前结点为叶子结点,则打印
			if (p->lson == nullptr)
			{
				cout << p->leter;
				p = root;
			}
			//否则就找当前结点的右子树
			p = p->rson;
		}
	}
}


//编码路径
string encodingPath(HFptr root, HFptr p)
{
	string x, y;
	HFptr q = p->parent;
	//由上向下记录路径
	while (q != root)
	{
		if (q->lson != p)
		{
			x += "1";
		}
		else
		{

			x += "0";
		}
		p = q;
		q = q->parent;
	}
	//判断最后一个结点是root的左子树还是右子树
	if (root->lson != p)
	{
		x += "1";
	}
	else
	{
		x += "0";
	}
	//路径由于是下往上,故需要反转
	for (int i = x.size() - 1; i != -1; i--)
	{
		y += x[i];
	}
	return y;
}

//哈夫曼树编码
void encoding(HFptr root, HFag set, int size)
{
	string str, x;
	cin >> str;
	for (size_t i = 0; i < str.size(); i++)
	{
		x = str[i];
		//遍历字符集里面的元素, 找到字母所对应的哈夫曼结点指针,再把对应的路径输出
		//set集合最后一个元素的下标为size - 1, 由于set之前输入是权重从大到小输入,
		//故权重越大出现的频率大的放到前面遍历,提高效率
		for (int j = size - 1; j != -1; j--)
		{
			if (x == set[j].leter)
			{
				cout << encodingPath(root, set[j].point);
			}
		}
	}
}



int main()
{
	HFptr root = nullptr;
	HFag set = nullptr;
	int size = 0;
	cout << "请输入字符个数:" << endl;
	cin >> size;
	createHFT(root, set, size);
	cout << "请输入编码的字符串:" << endl;
	encoding(root, set, size);
	cout << endl << "请输入译码的字符串:" << endl;
	decoding(root);
	cout << endl;

	system("pause");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值