数据结构与算法王卓-习题-第五章树和二叉树-哈夫曼编码

1. 简介

编写代码,能实现对用户输入的数据进行哈夫曼编码,返回哈夫曼编码表。

测试样例与输出

输入:

共7位数字,下图 i = 1~7中的weight (在测试时0.4将用40代替,0.3用30代替,0.15用15代替,以此类推)。

TIP:如果要用小数输入,请将代码部分int 改为 float

输出:

HC[i],即哈夫曼编码表。

数据结构与算法王卓-习题-第五章树和二叉树-哈夫曼编码_第1张图片

2. 代码

#include 
using namespace std;

typedef struct {
	int weight; 
	int parent, lchild, rchild; 
}HTNode,*Huffmantree;

typedef char** Huffmancode;

int HTinit(Huffmantree &t) {
	cout << "creating huffmantree: how many characters do you have in this huffmantree?\n";
	int n; cin >> n;
	if(!(t = new HTNode[2*n])) cout << "create failed: space error\n";//请求不到空间
	for (int i = 1; i < 2*n; i++) {
		t[i].weight = t[i].parent = t[i].lchild = t[i].rchild = 0;
	}
	for (int i = 1; i < n + 1; i++) {
		cout << "please enter the " << i<<": ";
		cin>>t[i].weight;
	}
	for (int i = 1; i < 2*n; i++) {
		cout << t[i].weight;
	}
	cout << "\n***HT created successful***\n" << endl;
	return 2 * n;
}

void HTstart(Huffmantree &a, int n) {
	cout << "ordering huffmantree...\n";
	int s1, s2, s1flag, s2flag,temp,i;
	for (temp = n / 2 + 1; temp < n; temp++) { //temp为目前操作的位置
		s1 = s2 = int('int'); s1flag = s2flag = NULL;
		for (i = 1; i < n; i++) {
			if (s1 > a[i].weight && a[i].weight && a[i].parent == 0) {
				s2 = s1;
				s2flag = s1flag;
				s1 = a[i].weight;
				s1flag = i;
			}
			else if (s2 > a[i].weight && a[i].weight && a[i].parent == 0) {
				s2 = a[i].weight;
				s2flag = i;
			}
		}
		a[temp].weight = s1 + s2; //给父母赋值
		a[temp].lchild = s1flag; a[temp].rchild = s2flag; //给父母标记左右孩
		a[s1flag].parent = a[s2flag].parent = temp; //给孩子标记父母
	}
	cout << "***ordering huffmantree completed***\n";
}

void HTshow(Huffmantree a, int n) {
	cout << "showing huffmantree..."<< endl; 
	for (int i = 1; i < n; i++) {
		cout << "number " << i << " is " << a[i].weight << " parent is in " << a[i].parent << " child is" << a[i].lchild <<" and " << a[i].rchild << endl;
	}
}

void HuffmanEncode(Huffmantree a, Huffmancode &HC, int n){ //这里形参怎么定义卡了很久
	cout << "\n***trying huffman coding***\n"; 
	HC = new char *[n + 1];    //HC为每个元素为字符串的数组,给序号列开辟空间(带星号)
	char *p = new char[n];     //p为临时存放编码的数组
	for (int i = 1; i <= n; i++) {
		int prt, now, sp = 0;
		prt = a[i].parent; now = i;
		while (prt) {
			if (now == a[prt].lchild) p[sp] = '0'; //一定要记住加引号啊!!!
			else p[sp] = '1';
			now = prt; prt = a[prt].parent; sp++;
		}
		p[sp] = 0;            //置0效果等同于'\0',代表结束,可以省,但上面那个不能省!
		HC[i] = new char[sp]; //HC为每个元素为字符串的数组,这一行是给每个字符串开辟空间
		for (int j = sp; j >= 0; j--)
		{
			HC[i][sp-j] = p[j-1];
		}                     //给HC编码表赋值,注意j的取值,若为j>0就会导致少一位
		HC[i][sp] = 0;        //因为j等于0时,HC[sp]=p[-1], 如果不置0则输出会带乱码
	}  
	delete p;
	cout << "***huffman coding completed***\n";
	for (int j = 1; j <= n; j++)
	{
		cout << a[j].weight << " code is " << HC[j] << endl;
	}                         //输出编码结果
}

int main(){
	Huffmantree a; Huffmancode HC;
	int n = HTinit(a);
	HTstart(a, n);
	HTshow(a,n);
	HuffmanEncode(a, HC, n/2);
	return 0;
}

输出

数据结构与算法王卓-习题-第五章树和二叉树-哈夫曼编码_第2张图片

数据结构与算法王卓-习题-第五章树和二叉树-哈夫曼编码_第3张图片

可以根据结果倒推出图,和老师的左右子树顺序不同但正确。印证了哈夫曼树不唯一性的特点。

构造哈夫曼树部分的代码取自我上一篇博客:

【3月第五周学习记录】数据结构与算法王卓-第五章树和二叉树-哈夫曼树(构造算法篇)_Finale_R的博客-CSDN博客

感想

在本题的算法部分花的时间远远少于其他题目(如构造哈夫曼树,主要功夫就是算法),主要卡在了数据结构上:

作为非科班出生,大部分时间花在理解char **,char *[], 形参如何声明,如何new space上了。

还吃了一个大亏就是给char赋值的时候,a=0 和 a='0'的巨大差别一定一定要敏锐。

希望我犯下的种种闹心错误能通过总结来节省你的时间,希望你不再犯同样的错,共勉。

参考资料

同时也十分感谢前辈的经验给我灵感,谢谢你们的耕耘

哈夫曼编码的实现_时间领主大锤的博客-CSDN博客_哈夫曼编码实现

C 函数参数 char **s与char *s[] - 张雅宸 - 博客园

你可能感兴趣的:(数据结构与算法习题,数据结构,算法,霍夫曼树,编码算法,决策树)