哈夫曼编码译码的应用(0.9a版)

一. 设计思路

1. 生成明文的 { 字符 + 权 } 集

2. 构造Huffman树(贪心法 + 自底向上)

3. 利用Huffman树,对明文进行编码

4. 利用huffman树,对编码译码为明文

二. 生成明文的 { 字符 + 权 } 集

1. 字符表:包括字符项目和权值项。

<span style="font-size:14px;">#define N 256

//字符表
struct charcode 
{
	char c; //字符
	int w;  //权值
};

struct charcode ctable[N];

//全局变量,明文中出现的字符个数
int num = 0;</span>

2. 在字符表中查找字符

<span style="font-size:14px;">//在字符表中查找字符,成功找到则返回字符位置;不成功返回-1
int find (char ch)
{
	int i;
	for(i = 0; ctable[i].c != 0; i++)
	{
		if(ctable[i].c == ch) //找到字符
		{
			return i;
		}
	}

	return i;//未找到
}</span>

3. 然后记录字符出现的频率(权值)

<span style="font-size:14px;">//在字符表中查找字符,成功返回字符位置;不成功返回0
//然后记录字符出现的频率(权值)
void getweight()
{
	char ch;
	freopen("plaintext.txt", "r", stdin);
	while((ch=getchar())!=EOF)
	{
		int i = find(ch);//查找字符位置
		if(!ctable[i].c)//若字符表相应的位置未存放字符
		{
			ctable[i].c = ch;//存入字符
			num++;	//字符数加1
		}
		ctable[i].w++; //权值加1
	}
	fclose(stdin);
}</span>

二. 构造Huffman树

1. Huffman树结构:字符,权,父亲下标,左孩子下标,右孩子下标

<span style="font-size:14px;">//Huffman树结构:字符,权,父亲下标,左孩子下标,右孩子下标
struct treenode//静态链表
{
	char c; //char
	int w;  //weight
	int f;  //father
	int l;  //left child index
	int r;  //right child index
};

//N个外部结点,总结点不超过2N - 1
struct treenode htree[2 * N - 1];</span>

2. 按权值排序

<span style="font-size:14px;">//使用选择法进行排序
void sort()
{
	int i,j;
	struct charcode t;

	for(i = 0; i < num; i++) //每次选择最小的权值
	{
		int m = i; //m记录最小权值的下标
		for(j = i + 1; j < num; j++)
		{
			if(ctable[j].w < ctable[m].w)
			{
				m = j;
			}
		}

		t = ctable[m];
		ctable[m] = ctable[i];
		ctable[i] = t;
	}
}</span>

三. 构建Huffman树

<span style="font-size:14px;">//使用贪心法建立Huffman树,每次选择权值最小的根节点
void huffman()
{
	int i, j, k, n;

	for(i = 0; i < num; i++)
	{
		//初始化哈夫曼表
		htree[i].c = ctable[i].c;
		htree[i].w = ctable[i].w;
		htree[i].l = htree[i].f = htree[i].r = -1;

		//printf("[%d]%c: %d\n",i, htree[i].c, htree[i].w);
	}

	j = 0;//j记录叶子节点的下标
	k = num;//K记录内部节点的下标

	for(n = num; n < 2 * num -1; n++)
	{//每次选择权值最小
		int r = 0, s = 0;
		htree[n].l = htree[n].f = htree[n].r = -1;

		while(r < 2)
		{
			if(htree[k].w == 0 || htree[k].w > htree[j].w && j < num)
			{
				s+=htree[j].w;//加入父亲的权值
				if(r == 0)
				{
					htree[n].l = j;//左孩子
				}
				else
				{
					htree[n].r = j;//右孩子
				}

				htree[j].f = n;//父亲
				j++;
			}
			else
			{//选择内部结点
				s+=htree[k].w;
				if(r == 0)
				{
					htree[n].l = k;
				}
				else
				{
					htree[n].r = k;
				}
				htree[k].f = n;
				k++;
			}
			r++;
		}

		htree[n].w = s;//父亲的权值
	}
}</span>

四. Huffman编码

<span style="font-size:14px;">//从plaintext.txt中读入明文,生成编码,存入telgraph.txt中
void encode()
{
	char ch;
	freopen("plaintext.txt", "r", stdin);
	freopen("telegraph.txt", "w", stdout);

	char* str= (char*)malloc(sizeof(char) * N);

	while((ch=getchar()) != EOF)
	{
		int i = find(ch);
		memset(str,0,sizeof(char) * N);
		getcode(i, str);
		printf("%s", str);
	}
	fclose(stdout);
	fclose(stdin);
	//free(str);
}</span>

<span style="font-size:14px;">//根据字符所在的下标,从叶子节点往上搜索到根节点
//然后逆置得到该字符的huffman编码
void getcode(int i, char* str)
{
	int n, j, l = 0;
	for(n = i;htree[n].f != -1; n = htree[n].f)
	{//沿着父亲往上搜索
		int m = htree[n].f;
		if(n == htree[m].l)
		{
			str[l++] = '0';//左孩子记为0
		}
		else
		{
			str[l++] = '1';//右孩子记为1
		}
	}

	for(j = 0; j <= (l -1)/2;j++)
	{//将编码逆置
		char t;
		t = str[j];
		str[j] = str[l - 1 -j];
		str[l - 1 - j] = t;
	}
	str[l] = '\0';//str存放huffman编码,字符串结束标记
}</span>

五. Huffman译码 

<span style="font-size:14px;">//从telgraph.txt中读入编码,译码为明文
//存入tanslation.txt
void decode()
{
	char ch;
	freopen("telegraph.txt", "r", stdin);
	freopen("tanslation.txt", "w", stdout);
	ch = getchar();

	//根据编码,从根节点往下搜索到叶子节点,得到该编码的字符
	while(ch != EOF)
	{
		int i;
		for(i = 2 * num - 2; htree[i].l != -1;)
		{
			if(ch == '0')
			{
				i = htree[i].l;
			}
			else
			{
				i = htree[i].r;
			}
			ch = getchar();
		}
		printf("%c", htree[i].c);
	}
	 fclose(stdout);
	 fclose(stdin);
}</span>

六. 主函数

<span style="font-size:14px;">//思路:主函数实现实验任务的基本流程
int _tmain(int argc, _TCHAR* argv[])
{
	getweight();//记录字符出现的频率(权值)
	sort();//权值排序
	huffman();//建立Huffman树
	encode();//编码
	decode();//译码
	return 0;
}</span>

七. VC 2008 HumanTest 案例 http://download.csdn.net/detail/u013354805/8849497

你可能感兴趣的:(哈夫曼编码译码哈夫曼树代码)