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中
⑷、重复⑵, ⑶,直到F只含一棵树为止

Huffman编码算法:
⑴、从Huffman树的每一个叶子结点开始
⑵、依次沿结点到根的路径,判断该结点是父亲结点的左孩子还是右孩子,如果是左孩子则得到编码‘0’,否则得到编码‘1’,先得到的编码放在后面
⑶、直到到达根结点,编码序列即为该叶子结点对应的Huffman编码

Huffman译(解)码算法:
⑴、指针指向Huffman树的根结点,取第一个Huffman码
⑵、如果Huffman码为‘0’,将指针指向当前结点的左子树的根结点;如果Huffman码为‘1’,将指针指向当前结点的右子树的根结点
⑶、如果指针指向的当前结点为叶子结点,则输出叶子结点对应的字符;否则,取下一个Huffman码,并返回⑵

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


输入

第一行:样本字符个数,假设为n。
第二行,n个字符(用空格隔开)
第三行,n个字符对应的权值(用空格隔开)
第四行,待编码的字符串
第五行,待译码的Huffman码序列

输出

第一行,每个字符对应的Huffman编码(用空格隔开)
第二行,字符串对应的Huffman编码序列
第三行,Huffman码序列对应的字符串


样例输入

4
a b c d
9 3 2 6
abcd
111001010

样例输出

0 101 100 11
010110011
dcba

 

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <stack>
#include <vector>
using namespace std;
#define Max_code_len 15
#define Max_tree_size 10 
const int inf=2147483647;
int n;
int w[1005];
char cc[1005];
char tm[1005];
struct node
{ 
	char c;
	int weight;
	int fa;
	int lc,rc;
	char code[Max_code_len];  
};
 

  node HT[2*Max_tree_size];
void  select(int nn,int&s1,int &s2)
{
	int minn=inf;
	int min_num=0;
	int i;
	for (i=1;i<=nn;i++)
	{
		if (HT[i].fa!=0) continue;
		if (HT[i].weight<minn)
		{
			minn=w[i];
			min_num=i;
		}
	}
	s1=min_num;
	minn=inf;
		for (i=1;i<=nn;i++)
	{
		if (HT[i].fa!=0||i==s1) continue;
		if (HT[i].weight<minn)
		{
			minn=w[i];
			min_num=i;
		}
	}
		s2=min_num;


}
void CreateHuffmanTree(char *cc,int *w) 
{
	int i;
	int m=2*n-1;
	for (i=1;i<=n;i++)
	{
		HT[i].fa=0;
		HT[i].c=cc[i];
		HT[i].weight=w[i];
		HT[i].lc=HT[i].rc=0;
	}
	for (;i<=m;i++)
	{
		HT[i].weight=0;
		HT[i].fa=HT[i].lc=HT[i].rc=0;
	}
	int s1,s2;
	for (i=n+1;i<=m;i++)
	{
		select(i-1,s1,s2);
		
		HT[s1].fa=HT[s2].fa=i;
		HT[i].lc=s1;
		HT[i].rc=s2;
		HT[i].weight=HT[s1].weight+HT[s2].weight;
	}
}
void HuffmanCoding()
{
	char cd[Max_code_len];
	int m=Max_code_len;
	cd[m-1]=0;
	int st;
	int c;
	int f;
	int i,j;
	for (i=1;i<=n;i++)
	{
		st=m-1;
		for (c=i,f=HT[i].fa;f!=0;)
		{
			if (c==HT[f].lc)
				cd[--st]='0';
			else
				cd[--st]='1';

			c=f;f=HT[f].fa;
		}
		for (j=st;j<m-1;j++)
			HT[i].code[j-st+1]=cd[j];
		HT[i].code[j-st+1]=0;
	}
}
void  ShowHuffmanCode()
{
	int i;
	for(i=1;i<n;i++)
		printf("%s ",HT[i].code+1);
	printf("%s\n",HT[i].code+1);
}
int ShowHuffmanEncode(char *tm) 
{
	int i,j;
	int len=strlen(tm);
	for (i=0;i<len;i++)
	{
		for (j=1;j<=n;j++)
		{
			if (tm[i]==HT[j].c)
			{ 
				printf("%s",HT[j].code+1);
			break; 
			}
		}
		if (i+1>=n) break;
	}
	printf("\n");
	return 0;
}
int ShowHuffmanDecode(char *tm) 
{
	int i,c,root;
	root=2*n-1;
	c=root;
	int len=strlen(tm);
	for (i=0;i<len;i++)
	{
		if (HT[c].lc==0&&HT[c].rc==0)
		{
			printf("%c",HT[c].c);
			c=root;
		}
		if (tm[i]=='0') 
		  c=HT[c].lc; 
		else 
		 	c=HT[c].rc;  
	}
	printf("%c\n",HT[c].c);

return 0;
}
int main()
{

	cin>>n;
	int i;
		for (i=1;i<=n;i++)
		cin>>cc[i];
	for (i=1;i<=n;i++)
		cin>>w[i];

	CreateHuffmanTree(cc,w);
	HuffmanCoding();
	ShowHuffmanCode();
	scanf("%s",tm+1); 
	ShowHuffmanEncode( tm+1);
	scanf("%s",tm+1); 
	ShowHuffmanDecode(tm+1);
	return 0;
	
}

你可能感兴趣的:(Huffman编码的设计与应用)