树12——哈夫曼树
哈夫曼树
为一组权值分别为2、4、7、15的结点序列构造一棵哈夫曼树,然后输出相应的哈夫曼编码。
为了便于设计,可利用一个二维数组实现哈夫曼树的算法。因为需要保存字符的权重、双亲结点位置、左孩子结点位置和右孩子结点的位置。所以需要将数组设计成n行四列。因此,哈夫曼树的类型定义如下:
typedef struct
{
unsigned int weight;
unsigned int parent,lchild,rchild;
}HTNode,*HuffmanTree;
typedef char **HuffmanCode;
定义一个类型为HuffumanCode的变量HT,用来存放每一个叶子结点的哈夫曼编码。初始时,将每一个叶子结点的双亲结点域、左孩子域和右孩子域初始化为0。如果有n个叶子结点,则非叶子结点有n-1个,所以总共节点数目是2*n-1个。同时也要将剩下的n-1个双亲结点域初始化为0,这主要是为了查找权值最小的结点方便。
依次选择两个权值最小的结点,分别作为左子树结点和右子树结点,修改他们的双亲结点域,使它们指向同一个双亲节点,同时修改双亲结点的权值,使其等于两个左、右子树结点权值的和,并修改左、右孩子结点域,使其分别指向左、右孩子结点。重复执行这种操作n-1次,即求出n-1个非叶子结点的权值。这样就得到了一棵哈夫曼树。
通过求得的哈夫曼树,得到每一个叶子结点的哈夫曼编码。从叶子结点c开始,通过结点c的双亲结点域,找到结点的双亲,然后通过双亲结点左孩子域和右孩子域判断该结点c是其双亲结点的左孩子还是右孩子,如果是左孩子,则编码为‘0’,否则编码为‘1’。按照这种方法,直到找到根结点,即可以求出叶子结点的编码。
code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <iostream>
using namespace std;
#define infinity 10000
typedef struct
{
unsigned int weight;
unsigned int parent, lchild, rchild;
}HTNode, *HuffmanTree;
typedef char **HuffmanCode;
int Min(HuffmanTree t, int n);
void Select(HuffmanTree *t, int n, int *s1, int *s2);
void HuffmanCoding(HuffmanTree *HT, HuffmanCode *HC, int *w, int n);
void main()
{
HuffmanTree HT;
HuffmanCode HC;
int *w, n, i;
cout << "请输入叶子结点的个数:";
cin >> n;
w = (int *)malloc(n*sizeof(int));
for (i = 0; i < n;i++)
{
cout << "请输入第" << i + 1 << "个结点的权值:";
cin >> w[i];
}
HuffmanCoding(&HT, &HC, w, n);
for (i = 1; i <= n;i++)
{
cout << "权值为" << w[i - 1] << "的哈夫曼编码:";
cout << HC[i] << endl;
}
for (i = 1; i <= n;i++)
{
free(HC[i]);
}
free(HC);
free(HT);
system("pause");
}
void HuffmanCoding(HuffmanTree *HT, HuffmanCode *HC, int *w, int n)
{
int m, i, s1, s2, start;
unsigned int c, f;
HuffmanTree p;
char *cd;
if (n<=1)
{
return;
}
m = 2 * n - 1;
*HT = (HuffmanTree)malloc((m + 1)*sizeof(HTNode));
for (p = *HT + 1, i = 1; i <= n;i++,p++,w++)
{
(*p).weight = *w;
(*p).parent = 0;
(*p).rchild = 0;
(*p).lchild = 0;
}
for (; i <= m;i++,p++)
{
(*p).parent = 0;
}
for (i = n + 1; i <= m;++i)
{
Select(HT, i - 1, &s1, &s2);
(*HT)[s1].parent = (*HT)[s2].parent = i;
(*HT)[i].lchild = s1;
(*HT)[i].rchild = s2;
(*HT)[i].weight = (*HT)[s1].weight + (*HT)[s2].weight;
}
*HC = (HuffmanCode)malloc((n + 1)*sizeof(char*));
cd = (char*)malloc(n*sizeof(char));
cd[n - 1] = '\0';
for (i = 1; i <= n;i++)
{
start = n - 1;
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));
strcpy((*HC)[i], &cd[start]);
}
}
free(cd);
}
int Min(HuffmanTree t, int n)
{
int i, flag;
int f = infinity;
for (i = 1; i <= n;i++)
{
if (t[i].weight<f&&t[i].parent==0)
{
f = t[i].weight, flag = i;
}
}
t[flag].parent = 1;
return flag;
}
void Select(HuffmanTree *t, int n, int *s1, int *s2)
{
int x;
*s1 = Min(*t, n);
*s2 = Min(*t, n);
if ((*t)[*s1].weight>(*t)[*s2].weight)
{
x = *s1;
*s1 = *s2;
*s2 = x;
}
}
结果: