首先给出构造哈夫曼树的代码
void HufmanCoding(HuffmanTree& HT, int* w,char*l, int n)
/*构造可编码n个元素的哈夫曼树HT,*/
{
status Select(HuffmanTree & HT, int& s1, int& s2);
if (n <= 1)return;
int m = 2 * n - 1;
HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNote));
if (!HT)exit(OVERFLOW);
HuffmanTree p; int i = 1; int s1, s2;
for (p = HT + 1; i <= n; ++p, ++i, ++w,++l)
{
p->letter = *l; p->weight = *w; p->parent = 0; p->lchild = 0; p->rchild = 0;
};//初始化n个数据//
for (; i <= m; ++i, ++p) { p->letter = '#'; p->weight = 0; p->parent = 0; p->lchild = 0; p->rchild = 0; }//初始化所有元素//
for (i = n + 1; i <= m; ++i)//建立哈夫曼树//
{
Select(HT, s1, s2);
HT[s1].parent = i;
HT[s2].parent = i;
HT[i].lchild = s1; HT[i].rchild = s2;
HT[i].weight = HT[s1].weight + HT[s2].weight;
}
return;
}
status Select(HuffmanTree& HT, int& s1, int& s2)
/*挑选哈夫曼树表中权值最小的两个点,两两结合*/
{
HuffmanTree p = HT + 1; int min1, min2;
while (p->parent) { p++; }
min1 = p->weight;
s1 = p - HT;
p++;
while (p->parent)p++;
min2 = p->weight;
s2 = p - HT;
if (min1 > min2) {
int t = 0;
t = min1; min1 = min2; min2 = t;
t = s1; s1 = s2; s2 = t;
}
while (p->weight) {
if (min1 > p->weight && !p->parent) {
min1 = p->weight; s1 = p - HT;
}
p++;
}
p = HT + 1;
while (p->weight) {
if (min2 > p->weight && !p->parent && p - HT != s1) {
min2 = p->weight; s2 = p - HT;
}
p++;
}
return ok;
}
在select函数中遇到很多麻烦,s1,s2要赋初值时,就要先检查赋的值是未被选择过的,由于要同时找出数组中的最小值s1和第二小s2,所以先后做两次循坏筛选。(我没有找到可以在一次循坏中一起找到两个数的办法。因为s1,s2可能一开始就赋值最小值,所以无法用记录下s1前一个数来表示s2。)
下面是哈夫曼树生成编码的代码
void encode(HuffmanTree& HT, HuffmanCode& HC,int n)
/*用哈夫曼树生成编码*/
{
char* cd = (char*) malloc(n*sizeof(char));
cd[n-1]='\0';
HC = (HuffmanCode)malloc( (n+1)*sizeof(char *) );
if (!HC)exit(Error);
int i;
for (i = 1; i <= n; ++i)
{
int start = n - 1;
int c, f;
for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent )
{
if (HT[f].lchild == c) cd[--start] = '0';
else cd[--start] = '1';
}
HC[i] = (char*)malloc((n-start) * sizeof(char));
if (!HC[i])exit(OVERFLOW);
strcpy_s(HC[i], strlen(cd)+1, &cd[start]);
}
利用哈夫曼树生成编码算法从叶子结点向上找双亲结点,如果是双亲结点的左孩子就纪录‘0’,右孩子就纪录‘1’,直到找到根结点。然后申请一个存放编码的HC[i]的数组指针。
注意:!!
最后strcpy_s中,从cd[start]的位置往后读,不将前面的没有赋值的赋值到HC[i],因为编码的个数是不尽相同的。
然后是销毁哈夫曼树的代码
void DestroyTree(HuffmanTree& HT)
/*销毁哈夫曼德树*/
{
if (!HT)return;
free(HT);
HT = NULL;
return;
}
void DestroyCode(HuffmanCode& HC,int n)
{
free(HC); HC = NULL;
return;
}
销毁HC时
我发现不需要对HC[i]先进行销毁,否则会报错
最后,记录一个让我耗时很久的低级错误
他是这样报错的
还有这样报错的
我挣扎了很久之后发现错在这里
cd[n-1]=(char)"\0";
我把单引号达成了双引号,然后系统将”\0“看作两个字符,报错溢出