核心算法如下
PhuffmanTree createHuffmanTree(int * a, int n) {
PhuffmanTree p[n];
PhuffmanTree ptr, root = NULL;
int i, j;
for (i = 0; i < n; i++) {
ptr = (PhuffmanTree)malloc(sizeof(huffmanTreeNode));
ptr->value = a[i];
ptr->left = ptr->right = NULL;
p[i] = ptr;
}
for (i = 1; i < n; i++) {
int k1 = -1, k2;
for (j = 0; j < n; j++) {
if (p[j] != NULL && k1 == -1) {
k1 = j;
continue;
}
if (p[j] != NULL) {
k2 = j;
break;
}
}
for (j = k2; j < n; j++) {
if (p[j] != NULL) {
if (p[j]->value < p[k1]->value) {
k2 = k1;
k1 = j;
} else if (p[j]->value < p[k2]->value) {
k2 = j;
}
}
}
root = (PhuffmanTree)malloc(sizeof(huffmanTreeNode));
root->value = p[k1]->value + p[k2]->value;
root->left = p[k1];
root->right = p[k2];
p[k1] = root;
p[k2] = NULL;
}
return root;
}
电报通信中,电文是以二进制的0、1序列传送的,每个字符对应一个二进制编码,为了缩短电文的总长度,采用不等长编码方式,构造哈夫曼树,
将每个字符的出现频率作为字符结点的权值赋予叶子结点,每个分支结点的左右分支分别用0和1编码,从树根结点到每个叶子结点的路径上
所经分支的0、1编码序列等于该叶子结点的二进制编码。所示的哈夫曼编码如下:
15:01
18:11
8:100
5:1011
2:10100
3:10101
具体实现如下
#include<stdio.h>
#include<stdlib.h>
typedef struct huffmanTree * Tree;
typedef struct huffmanTree {
int value;
Tree left;
Tree right;
}huffmanTreeNode, * PhuffmanTree;
PhuffmanTree createHuffmanTree(int * a, int n) {
PhuffmanTree p[n];
PhuffmanTree ptr, root = NULL;
int i, j;
for (i = 0; i < n; i++) {
ptr = (PhuffmanTree)malloc(sizeof(huffmanTreeNode));
ptr->value = a[i];
ptr->left = ptr->right = NULL;
p[i] = ptr;
}
for (i = 1; i < n; i++) {
int k1 = -1, k2;
for (j = 0; j < n; j++) {
if (p[j] != NULL && k1 == -1) {
k1 = j;
continue;
}
if (p[j] != NULL) {
k2 = j;
break;
}
}
for (j = k2; j < n; j++) {
if (p[j] != NULL) {
if (p[j]->value < p[k1]->value) {
k2 = k1;
k1 = j;
} else if (p[j]->value < p[k2]->value) {
k2 = j;
}
}
}
root = (PhuffmanTree)malloc(sizeof(huffmanTreeNode));
root->value = p[k1]->value + p[k2]->value;
root->left = p[k1];
root->right = p[k2];
p[k1] = root;
p[k2] = NULL;
}
return root;
}
int caculateWeightLength(PhuffmanTree pTree, int len) {
if (!pTree) {
return 0;
} else {
if (pTree->left == NULL && pTree->right == NULL) {
return pTree->value * len;
} else {
return caculateWeightLength(pTree->left, len+1) + caculateWeightLength(pTree->right, len+1);
}
}
}
void huffmanCode(PhuffmanTree pTree, int len) {
static int arr[20];
if (pTree) {
if (pTree->left == NULL && pTree->right == NULL) {
printf("节点权值为%d的编码:", pTree->value);
for (int i = 0; i < len; i++) {
printf("%d", arr[i]);
}
putchar('\n');
} else {
arr[len] = 0;
huffmanCode(pTree->left, len+1);
arr[len] = 1;
huffmanCode(pTree->right, len+1);
}
}
}
void printNode(PhuffmanTree node) {
if (node->left == NULL && node->right == NULL) {
printf("叶子节点x = %d\n\n", node->value);
return ;
}
if (node->left != NULL) {
printf("x = %d为哈夫曼树中左子树节点是lnode = %d\n", node->value, node->left->value);
}
if (node->right != NULL) {
printf("x = %d为哈夫曼树中右子树节点是rnode = %d\n", node->value, node->right->value);
}
putchar('\n');
}
void prePrint(PhuffmanTree pTree) {
if (!pTree) {
return ;
} else {
printNode(pTree);
prePrint(pTree->left);
prePrint(pTree->right);
}
}
void midPrint(PhuffmanTree pTree) {
if (!pTree) {
return ;
} else {
midPrint(pTree->left);
printf("%d ", pTree->value);
midPrint(pTree->right);
}
}
void postPrint(PhuffmanTree pTree) {
if (!pTree) {
return ;
} else {
postPrint(pTree->left);
postPrint(pTree->right);
printf("%d ", pTree->value);
}
}
void giveNum(int * a, int n) {
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
}
int main(void)
{
int arr[] = {}, n, flag;
printf ("输入带权节点个数:");
scanf("%d", &n);
giveNum(arr, n);
PhuffmanTree root = createHuffmanTree(arr, n);
printf("1.中序遍历 2.先序遍历哈夫曼树节点关系 3.后序遍历\n");
printf("4.带权路径长度 5.哈夫曼树编码 6.创建哈夫曼树 7.退出\n");
while (scanf("%d", &flag) != EOF && flag != 7) {
switch (flag) {
case 1: midPrint(root);printf("\n\n");break;
case 2: printf("哈夫曼树节点关系如下\n");prePrint(root);break;
case 3: postPrint(root);printf("\n\n");break;
case 4: printf("带权路径长度\n");printf("WeightLength=%d\n\n",
caculateWeightLength(root,0));break;
case 5:printf("各节点编码如下:\n");huffmanCode(root,0);putchar('\n');break;
case 6:printf ("输入带权节点个数:");scanf("%d", &n);giveNum(arr, n);
root = createHuffmanTree(arr, n);break;
}
printf("1.中序遍历 2.先序遍历哈夫曼树节点关系 3.后序遍历\n");
printf("4.带权路径长度 5.哈夫曼树编码 6.创建哈夫曼树 7.退出\n");
}
return 0;
}
结果如图所示