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!

 

其它组测试数据类推

 

样例输入

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

样例输出

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

 

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

const int maxw = 9999;

class HuffNode{
public:
	int weight;
	int parent;
	int leftchild;
	int rightchile;
};

class HuffMan{
private:
	void MakeTree()
	{
		int i, s1, s2;
		for (i = lnum + 1; i <= len; i++)
		{
			SelectMin(i - 1, &s1, &s2);
			hufftree[s1].parent = i;
			hufftree[s2].parent = i;
			hufftree[i].leftchild = s1;
			hufftree[i].rightchile = s2;
			hufftree[i].weight = hufftree[s1].weight + hufftree[s2].weight;
		}
	}
	void SelectMin(int pos, int *s1, int *s2)
	{
		int w1, w2, i;
		w1 = w2 = maxw;
		*s1 = *s2 = 0;
		for (i = 1; i <= pos; i++)
		{
			if (hufftree[i].weight < w1 && hufftree[i].parent == 0)
			{
				*s2 = *s1;
				w2 = w1;
				w1 = hufftree[i].weight;
				*s1 = i;
			}
			else if (hufftree[i].weight < w2 && hufftree[i].parent == 0)
			{
				w2 = hufftree[i].weight;
				*s2 = i;
			}
		}
	}
public:
	int len;
	int lnum;
	HuffNode *hufftree;
	string *huffCode;
	char *message;
	void MakeTree(int n, int wt[], char c[])
	{
		int i;
		lnum = n;
		len = 2 * n - 1;
		hufftree = new HuffNode[2 * n];
		huffCode = new string[lnum + 1];
		message = new char[lnum + 1];
		for (i = 1; i <= n; i++) 
            hufftree[i].weight = wt[i - 1];
		for (i = 1; i <= n; i++)
            message[i] = c[i - 1];
		for (i = 1; i <= len; i++)
		{
			if (i > n)
                hufftree[i].weight = 0;
			hufftree[i].parent = 0;
			hufftree[i].leftchild = 0;
			hufftree[i].rightchile = 0;
		}
		MakeTree();
	}
	void Coiding()
	{
		char *cd = new char[lnum];
		int i, c, f, start;
		cd[lnum - 1] = '\0';
		for (i = 1; i <= lnum; i++)
		{
			start = lnum - 1;
			for (c = i, f = hufftree[i].parent; f != 0; c = f, f = hufftree[f].parent)
			{
				if (hufftree[f].leftchild == c)
					cd[--start] = '0';
				else
					cd[--start] = '1';
			}
			huffCode[i].assign(&cd[start]);
		}
	}
	void Destory()
	{
		len = 0;
		lnum = 0;
		delete[]hufftree;
		delete[]huffCode;
	}
	int Decode(const string codestr, string &teststr){
		int i, k, c;
		char ch;
		c = len;
		k = 0;
		string a = "";
		for (i = 0; i < codestr.length(); i++)
		{
			ch = codestr[i];
			a += ch;
			if (ch == '0') c = hufftree[c].leftchild;
			else
                if (ch == '1') 
                    c = hufftree[c].rightchile;
                else 
                    return 0;
			if (hufftree[c].leftchild == 0 && hufftree[c].rightchile == 0)
			{
				for (int j = 1; j <= lnum; j++)
					if (hufftree[c].weight == hufftree[j].weight && a == huffCode[j])
						teststr += message[j];
				c = len;
				a = "";
			}
			else ch = '\0';
		}
		if (ch == '\0') return 0;
		return 1;
	}
};

int main()
{
	int t, n, i, j;
	int wt[800];
	char c[800];
	string teststr = "";
	string codestr;
	HuffMan huff;
	cin >> t;
	while (t--)
	{
		cin >> n;
		for (i = 0; i < n; i++) cin >> c[i];
		for (i = 0; i < n; i++) cin >> wt[i];
		huff.MakeTree(n, wt, c);
		huff.Coiding();
		for (i = 1; i <= n; i++)
		{
			cout << c[i - 1] << " :" << huff.huffCode[i] << endl;
		}
		cin >> codestr;
		for (i = 0; i < codestr.length(); i++)
		{
			for (j = 1; j <= n; j++)
				if (codestr[i] == c[j - 1]) cout << huff.huffCode[j];
		}
		cout << endl;
		cin >> codestr;
		if (huff.Decode(codestr, teststr)) cout << teststr << endl;
		else cout << "error!" << endl;
		teststr = "";
		huff.Destory();
	}
	return 0;
}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值