哈夫曼树
Posted xiaoshuita
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了哈夫曼树相关的知识,希望对你有一定的参考价值。
这里讲的哈夫曼树有创建哈夫曼树,输出哈夫曼树,递归进行哈夫曼树编码,哈夫曼解码这些功能。
1.创建哈夫曼树:(函数参数为整型数组)
(1)引入哈夫曼树指针数组并申请空间,为每棵哈夫曼树复制,将其左右节点赋值为NULL。
(2)将(n-1)棵哈夫曼树合并:a.引入两个整形变量始终代表最小和次小的下标
b.比较权值,使两个下标成为最小的两个权值的下标
c.合并一次,并将最小下标的哈夫曼树赋值为新的哈夫曼树,次小下表的哈夫曼树赋值为空。
2.输出哈夫曼树:根节点不为空,输出权重,若左右子树不为空,依次输出“(”, 左子树,“,”,右子树,“)”
3.递归进行哈夫曼编码:由于哈夫曼树的特点是所有的原始树都为叶子节点,故可以用这方法来进行编码。
4.哈夫曼解码:while(已解码长度<字符串长度){找到某一叶子节点并打印}
以下是完整代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef int ELEMTYPE;
// 哈夫曼树结点结构体
typedef struct HuffmanTree
{
ELEMTYPE weight;
ELEMTYPE id; // id用来主要用以区分权值相同的结点,这里代表了下标
struct HuffmanTree* lchild;
struct HuffmanTree* rchild;
}HuffmanNode;
// 构建哈夫曼树
HuffmanNode* createHuffmanTree(int* a, int n)
{
int i, j;
HuffmanNode **temp, *hufmTree;
temp = (HuffmanNode **)malloc(n*sizeof(HuffmanNode));
for (i=0; i<n; ++i) // 将数组a中的权值赋给结点中的weight
{
temp[i] = (HuffmanNode*)malloc(sizeof(HuffmanNode));
temp[i]->weight = a[i];
temp[i]->id = i;
temp[i]->lchild = temp[i]->rchild = NULL;
}
for (i=0; i<n-1; ++i) // 构建哈夫曼树需要n-1合并
{
int small1=-1, small2; // small1、small2分别作为最小和次小权值的下标
for (j=0; j<n; ++j) // 先将最小的两个下标赋给small1、small2(注意:对应权值未必最小)
{
if (temp[j] != NULL && small1==-1)
{
small1 = j;
continue;
} else if(temp[j] != NULL)
{
small2 = j;
break;
}
}
for (j=small2; j<n; ++j) // 比较权值,挪动small1和small2使之分别成为最小和次小权值的下标
{
if (temp[j] != NULL)
{
if (temp[j]->weight < temp[small1]->weight)
{
small2 = small1;
small1 = j;
} else if (temp[j]->weight < temp[small2]->weight)
{
small2 = j;
}
}
}
hufmTree = (HuffmanNode*)malloc(sizeof(HuffmanNode));
hufmTree->weight = temp[small1]->weight + temp[small2]->weight;
hufmTree->lchild = temp[small1];
hufmTree->rchild = temp[small2];
temp[small1] = hufmTree;
temp[small2] = NULL;
}
free(temp);
return hufmTree;
}
// 以广义表的形式打印哈夫曼树
void PrintHuffmanTree(HuffmanNode* hufmTree)
{
if (hufmTree)
{
printf("%d", hufmTree->weight);
if (hufmTree->lchild != NULL || hufmTree->rchild != NULL)
{
printf("(");
PrintHuffmanTree(hufmTree->lchild);
printf(",");
PrintHuffmanTree(hufmTree->rchild);
printf(")");
}
}
}
// 递归进行哈夫曼编码
void HuffmanCode(HuffmanNode* hufmTree, int depth) // depth是哈夫曼树的深度
{
static int code[10];
if (hufmTree)
{
if (hufmTree->lchild==NULL && hufmTree->rchild==NULL)
{
printf("id为%d权值为%d的叶子结点的哈夫曼编码为 ", hufmTree->id, hufmTree->weight);
int i;
for (i=0; i<depth; ++i)
{
printf("%d", code[i]);
}
printf(" ");
} else
{
code[depth] = 0;
HuffmanCode(hufmTree->lchild, depth+1);
code[depth] = 1;
HuffmanCode(hufmTree->rchild, depth+1);
}
}
}
// 哈夫曼解码
void HuffmanDecode(char ch[], HuffmanNode* hufmTree, char string[]) // ch是要解码的01串,string是结点对应的字符
{
int i;
int num[100];
HuffmanNode* tempTree = NULL;
for (i=0; i<strlen(ch); ++i)
{
if (ch[i] == ‘0‘)
num[i] = 0;
else
num[i] = 1;
}
if(hufmTree)
{
i = 0; // 计数已解码01串的长度
while(i<strlen(ch))
{
tempTree = hufmTree;
while(tempTree->lchild!=NULL && tempTree->rchild!=NULL)
{
if (num[i] == 0)
{
tempTree = tempTree->lchild;
} else
{
tempTree = tempTree->rchild;
}
++i;
}
printf("%c", string[tempTree->id]); // 输出解码后对应结点的字符
}
}
}
int main()
{
int i, n;
printf("请输入叶子结点的个数: ");
while(1)
{
scanf("%d", &n);
if (n>1)
break;
else
printf("输入错误,请重新输入n值!");
}
int* arr;
arr=(int*)malloc(n*sizeof(ELEMTYPE));
printf("请输入%d个叶子结点的权值: ", n);
for (i=0; i<n; ++i)
{
scanf("%d", &arr[i]);
}
char ch[100], string[100];
printf("请连续输入这%d个叶子结点各自所代表的字符: ", n);
fflush(stdin); // 强行清除缓存中的数据,也就是上面输入权值结束时的回车符
gets(string);
HuffmanNode* hufmTree = NULL;
hufmTree = createHuffmanTree(arr, n);
printf("此哈夫曼树的广义表形式为: ");
PrintHuffmanTree(hufmTree);
printf(" 各叶子结点的哈夫曼编码为: ");
HuffmanCode(hufmTree, 0);
printf("要解码吗?请输入编码: ");
gets(ch);
printf("解码结果为: ");
HuffmanDecode(ch, hufmTree, string);
printf(" ");
free(arr);
free(hufmTree);
return 0;
}
以上是关于哈夫曼树的主要内容,如果未能解决你的问题,请参考以下文章