DS二叉树——Huffman编码与解码(不含代码框架)

题目描述

1、问题描述

给定n个字符及其对应的权值,构造Huffman树,并进行huffman编码和译(解)码。

构造Huffman树时,要求左子树根的权值小于、等于右子树根的权值。

进行Huffman编码时,假定Huffman树的左分支上编码为‘0’,右分支上编码为‘1’。

2、算法

构造Huffman树算法:

⑴根据给定的n个权值(w1, w2, …, wn)构成n棵二叉树的集合F={T1, T2, …, Tn},其中每棵二叉树Ti中只有一个权值为wi的根结点。

⑵在F中选取两棵根结点的权值最小的树,作为左、右子树构造一棵新的二叉树,且置其根结点的权值为其左、右子树权值之和。

⑶在F中删除这两棵树,同时将新得到的二叉树加入F中。

(4)重复⑵,⑶,直到F只含一棵树为止。

3、Huffman编码算法:

⑴从Huffman树的每一个叶子结点开始。

⑵依次沿结点到根的路径,判断该结点是父亲结点的左孩子还是右孩子,如果是左孩子则得到编码‘0’,否则得到编码‘1’,先得到的编码放在后面。

⑶直到到达根结点,编码序列即为该叶子结点对应的Huffman编码。

4、Huffman译(解)码算法:

⑴指针指向Huffman树的根结点,取第一个Huffman码。

⑵如果Huffman码为‘0’,将指针指向当前结点的左子树的根结点;如果Huffman码为‘1’,将指针指向当前结点的右子树的根结点。

⑶如果指针指向的当前结点为叶子结点,则输出叶子结点对应的字符;否则,取下一个Huffman码,并返回⑵。

⑷如果Huffman码序列未结束,则返回⑴继续译码。

输入

第一行测试次数

第2行:第一组测试数据的字符个数n,后跟n个字符

第3行:第一组测试数据的字符权重

待编码的字符串s1

编码串s2

其它组测试数据类推

输出

第一行~第n行,第一组测试数据各字符编码值

第n+1行,串s1的编码值

第n+2行,串s2的解码值,若解码不成功,输出error!

其它组测试数据类推

输入样例1

2
5 A B C D E
15 4 4 3 2
ABDEC
00000101100
4 A B C D
7 5 2 4
ABAD
1110110

输出样例1

A :1
B :010
C :011
D :001
E :000
1010001000011
error!
A :0
B :10
C :110
D :111
0100111
DAC

NOTICE:详细解释见注释。

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

class TNode
{
public:
	char data;
	int weight;
	int parent;
	int lchild;
	int rchild;
	string code;
};

class HuffmanTree
{
private:
	TNode* tree;
	int lnum;
	int nodenum;
public:
	HuffmanTree()
	{
		cin >> lnum;
		nodenum = 2 * lnum - 1;
		tree = new TNode[nodenum];
		for (int i = 0; i < lnum; i++)
		{
			cin >> tree[i].data;
		}
		for (int i = 0; i < lnum; i++)
		{
			cin >> tree[i].weight;
		}
		for (int i = 0; i < lnum; i++)
		{
			tree[i].parent = -1;
			tree[i].lchild = -1;
			tree[i].rchild = -1;
		}
	}
	void CreateHuffman()
	{
		int n = lnum;
		while (n != nodenum)
		{
			//寻找最小权值的两个结点
			int min1 = 9999, min2 = 9999;
			int index1 = 0, index2 = 0;
			for (int i = 0; i < n; i++)
			{
				if (tree[i].parent == -1 && tree[i].weight < min1)
				{
					min2 = min1;
					index2 = index1;
					min1 = tree[i].weight;
					index1 = i;
				}
				else if (tree[i].parent == -1 && tree[i].weight < min2)
				{
					min2 = tree[i].weight;
					index2 = i;
				}
			}
			//将两个结点合并
			tree[index1].parent = n;
			tree[index2].parent = n;
			tree[n].weight = tree[index1].weight + tree[index2].weight;
			tree[n].lchild = index1;
			tree[n].rchild = index2;
			tree[n].parent = -1;
			n++;
		}
	}
	void HuffmanCode()
	{
		for (int i = 0; i < lnum; i++)
		{
			int parent = tree[i].parent;
			int pre = i;//记录先前的结点
			while (parent != -1)
			{
				if (tree[parent].lchild == pre)
				{
					tree[i].code = "0" + tree[i].code;
				}
				else
				{
					tree[i].code = "1" + tree[i].code;
				}
				pre = parent;
				parent = tree[parent].parent;
			}
		}

		for (int i = 0; i < lnum; i++)
		{
			cout << tree[i].data << " :" << tree[i].code << endl;
		}
	}
	void Code(string s)
	{
		string res;
		for (int i = 0; i < s.size(); i++)
		{
			for (int j = 0; j < lnum; j++)
			{
				if (s[i] == tree[j].data)
				{
					res = res + tree[j].code;
					break;
				}
			}
		}
		cout << res << endl;
	}
	void Decode(string s)
	{
		string res;
		int i = 0;
		int k = nodenum - 1;
		while (i != s.size())
		{
			if (s[i] == '0')
			{
				k = tree[k].lchild;
			}
			else
			{
				k = tree[k].rchild;
			}
			i++;

			if (tree[k].lchild == -1 && tree[k].rchild == -1)
			{
				res = res + tree[k].data;
				k = nodenum - 1;
			}
		}
		if (k == nodenum - 1)//说明能解出最后一个字符
		{
			cout << res << endl;
		}
		else
		{
			cout << "error!" << endl;
		}
	}
};

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		HuffmanTree hft;
		hft.CreateHuffman();
		hft.HuffmanCode();
		string s;
		cin >> s;
		hft.Code(s);
		cin >> s;
		hft.Decode(s);
	}
	return 0;
}

​​

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值