#include <stdio.h>
#include <stdlib.h>
#define MAXINT 32767
// 哈夫曼树每一个结点的类型
typedef struct HuffmanTreeNodeType {
int weight; // 权值
int parent, lchild, rchild; // 双亲、左孩子、有孩子的位置
} HuffmanTreeNodeType;
// 找最小的根结点和次小的根结点
void MinSubmin(HuffmanTreeNodeType* HuffmanTree, int end, int* MinLocation, int* SubminLocation) {
int min = MAXINT, submin = MAXINT;
for (int i = 0; i <= end; i++) {
if (HuffmanTree[i].weight < min && HuffmanTree[i].parent == 0) {
submin = min;
*SubminLocation = *MinLocation;
min = HuffmanTree[i].weight;
*MinLocation = i;
}
else if (HuffmanTree[i].weight < submin && HuffmanTree[i].parent == 0) {
submin = HuffmanTree[i].weight;
*SubminLocation = i;
}
}
}
// 打印顺序表
void print(HuffmanTreeNodeType* HuffmanTree, int end) {
printf("\n索引\t权值\t双亲域\t左孩子域\t右孩子域\n");
for (int i = 0; i < end; i++) {
printf("%d\t%d\t%d\t%d\t\t%d\n", i, HuffmanTree[i].weight, HuffmanTree[i].parent, HuffmanTree[i].lchild, HuffmanTree[i].rchild);
}
}
// 创建哈夫曼树
void CreatHuffmanTree(HuffmanTreeNodeType** HuffmanTree, int n) {
// 先初始化一个数组,即哈夫曼树的初态
// 有n个结点,需要n-1次合并,共产生2n-1个结点
(*HuffmanTree) = (HuffmanTreeNodeType*)malloc(sizeof(HuffmanTreeNodeType) * (2 * n - 1));
// 每一个结点的四个域均初始化为0
for (int i = 0; i < 2 * n - 1; i++) {
(*HuffmanTree)[i].parent = 0;
(*HuffmanTree)[i].lchild = 0;
(*HuffmanTree)[i].rchild = 0;
(*HuffmanTree)[i].weight = 0;
}
// 读取n个结点的权值,存放在结点顺序表的前n个位置,索引从0到n-1
printf("请输入每一个结点的权值: ");
for (int i = 0; i < n; i++) {
scanf("%d", &(*HuffmanTree)[i].weight);
}
// 打印顺序表的初态
printf("\n顺序表的初态:\n");
print((*HuffmanTree), 2 * n - 1);
int MinLocation, SubminLocation;
// 在结点顺序表的后面n-1个位置上,每次找两个结点最小值,构成新结点
for (int i = n; i < 2 * n - 1; i++) {
MinSubmin((*HuffmanTree), i - 1, &MinLocation, &SubminLocation);
(*HuffmanTree)[i].lchild = MinLocation;
(*HuffmanTree)[i].rchild = SubminLocation;
(*HuffmanTree)[i].weight = (*HuffmanTree)[MinLocation].weight + (*HuffmanTree)[SubminLocation].weight;
(*HuffmanTree)[MinLocation].parent = i;
(*HuffmanTree)[SubminLocation].parent = i;
}
}
// 求每一个叶子结点的哈夫曼编码
void HuffmanCode(HuffmanTreeNodeType* HuffmanTree, char*** HuffmanCodeList, int n) {
(*HuffmanCodeList) = (char**)malloc(sizeof(char*) * n);
char* cd = (char*)malloc(sizeof(char) * n);
//cd[n - 1] = '\0';
memset(cd, '\0', sizeof(cd));
for (int i = 0; i < n; i++) {
int start = n - 1;
int cur = i;
int par = HuffmanTree[i].parent;
while (par != 0) {
--start;
if (HuffmanTree[par].lchild == cur)
cd[start] = '0';
else
cd[start] = '1';
cur = par;
par = HuffmanTree[cur].parent;
}
(*HuffmanCodeList)[i] = (char*)malloc(sizeof(char) * (n - start));
strcpy((*HuffmanCodeList)[i], &cd[start]);
}
free(cd);
}
// 打印哈夫曼编码
void PrintHuffmanCode(HuffmanTreeNodeType* HuffmanTree, char** HuffmanCodeList, int n) {
printf("各个叶子结点的哈夫曼编码为:\n");
for (int i = 0; i < n; i++)
printf("%d: %s\n", HuffmanTree[i].weight, HuffmanCodeList[i]);
}
int main(void) {
// 定义一棵哈夫曼树
HuffmanTreeNodeType* HuffmanTree;
// 定义结点个数
int n;
// 读入哈夫曼树的结点个数
printf("请哈夫曼树的结点个数: ");
scanf("%d", &n);
// 创建哈夫曼树
CreatHuffmanTree(&HuffmanTree, n);
// 打印顺序表的终态
printf("\n顺序表的终态:\n");
print(HuffmanTree, 2 * n - 1);
// 求每一个叶子结点的哈夫曼编码
// 定义一个字符串数组,每一个字符串对应着一个叶子结点的编码
char** HuffmanCodeList;
HuffmanCode(HuffmanTree, &HuffmanCodeList, n);
// 打印哈夫曼编码
printf("\n");
PrintHuffmanCode(HuffmanTree, HuffmanCodeList, n);
return 0;
}
执行结果:
请哈夫曼树的结点个数: 8
请输入每一个结点的权值: 5 29 7 8 14 23 3 11
顺序表的初态:
索引 权值 双亲域 左孩子域 右孩子域
0 5 0 0 0
1 29 0 0 0
2 7 0 0 0
3 8 0 0 0
4 14 0 0 0
5 23 0 0 0
6 3 0 0 0
7 11 0 0 0
8 0 0 0 0
9 0 0 0 0
10 0 0 0 0
11 0 0 0 0
12 0 0 0 0
13 0 0 0 0
14 0 0 0 0
顺序表的终态:
索引 权值 双亲域 左孩子域 右孩子域
0 5 8 0 0
1 29 13 0 0
2 7 9 0 0
3 8 9 0 0
4 14 11 0 0
5 23 12 0 0
6 3 8 0 0
7 11 10 0 0
8 8 10 6 0
9 15 11 2 3
10 19 12 8 7
11 29 13 4 9
12 42 14 10 5
13 58 14 1 11
14 100 0 12 13
各个叶子结点的哈夫曼编码为:
5: 0001
29: 10
7: 1110
8: 1111
14: 110
23: 01
3: 0000
11: 001