编写代码,能实现对用户输入的数据进行哈夫曼编码,返回哈夫曼编码表。
测试样例与输出
输入:
共7位数字,下图 i = 1~7中的weight (在测试时0.4将用40代替,0.3用30代替,0.15用15代替,以此类推)。
TIP:如果要用小数输入,请将代码部分int 改为 float
输出:
HC[i],即哈夫曼编码表。
#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;
}
输出
可以根据结果倒推出图,和老师的左右子树顺序不同但正确。印证了哈夫曼树不唯一性的特点。
构造哈夫曼树部分的代码取自我上一篇博客:
【3月第五周学习记录】数据结构与算法王卓-第五章树和二叉树-哈夫曼树(构造算法篇)_Finale_R的博客-CSDN博客
在本题的算法部分花的时间远远少于其他题目(如构造哈夫曼树,主要功夫就是算法),主要卡在了数据结构上:
作为非科班出生,大部分时间花在理解char **,char *[], 形参如何声明,如何new space上了。
还吃了一个大亏就是给char赋值的时候,a=0 和 a='0'的巨大差别一定一定要敏锐。
希望我犯下的种种闹心错误能通过总结来节省你的时间,希望你不再犯同样的错,共勉。
同时也十分感谢前辈的经验给我灵感,谢谢你们的耕耘
哈夫曼编码的实现_时间领主大锤的博客-CSDN博客_哈夫曼编码实现
C 函数参数 char **s与char *s[] - 张雅宸 - 博客园