给定权值{A:5,B:29,C:7,D:8,E:14,F:23,G:3,H:11}建立哈夫曼树,输出哈夫曼编码;对上述给定的哈夫曼树及得到的哈夫曼编码,试输入一串二进制编码,输出它的哈夫曼译码。
要求:将哈夫曼树的结构定义为一个一维数组,每个元素含有四顶:权值、双亲、左孩、右孩。权值由键盘输入;二进制编码时,往左走编码为0,往右走编码为1 ;译码就是将输入的编码还原成对应的字符
#include <stdio.h>
#include <stdlib.h>
// 定义哈夫曼树节点的结构
struct HuffmanNode {
int weight; // 权值
int parent; // 双亲节点索引
int left; // 左孩子节点索引
int right; // 右孩子节点索引
};
// 构建哈夫曼树
void buildHuffmanTree(struct HuffmanNode* nodes, int n) {
int i, j;
int m1, m2; // 最小和次小权值的节点索引
// 初始化所有节点的双亲、左孩子和右孩子索引为-1
for (i = 0; i < 2 * n - 1; i++) {
nodes[i].parent = -1;
nodes[i].left = -1;
nodes[i].right = -1;
}
// 输入各节点的权值
for (i = 0; i < n; i++) {
printf("请输入节点 %c 的权值:", i + 'A');
scanf("%d", &(nodes[i].weight));
}
// 构建哈夫曼树
for (i = 0; i < n - 1; i++) {
m1 = m2 = -1;
// 在尚未构建的节点中找到权值最小和次小的节点
for (j = 0; j < n + i; j++) {
if (nodes[j].parent == -1) {
if (m1 == -1 || nodes[j].weight < nodes[m1].weight) {
m2 = m1;
m1 = j;
} else if (m2 == -1 || nodes[j].weight < nodes[m2].weight) {
m2 = j;
}
}
}
// 设置找到的两个节点的双亲和左孩子/右孩子索引
nodes[m1].parent = n + i;
nodes[m2].parent = n + i;
nodes[n + i].left = m1;
nodes[n + i].right = m2;
nodes[n + i].weight = nodes[m1].weight + nodes[m2].weight;
}
}
// 生成哈夫曼编码
void generateHuffmanCode(struct HuffmanNode* nodes, int n, char** codes) {
int i, j;
char* code; // 存储临时编码
// 分配存储编码的内存空间
code = (char*)malloc(n * sizeof(char));
code[n - 1] = '\0'; // 编码结束符
// 从叶子节点向根节点回溯,生成哈夫曼编码
for (i = 0; i < n; i++) {
int start = n - 1;
// 从叶子节点开始回溯到根节点
for (j = i, start = n - 1; nodes[j].parent != -1; j = nodes[j].parent) {
if (nodes[nodes[j].parent].left == j) {
code[--start] = '0'; // 左孩子编码为0
} else {
code[--start] = '1'; // 右孩子编码为1
}
}
// 为第i个节点的编码分配内存空间并复制编码
codes[i] = (char*)malloc((n - start) * sizeof(char));
strcpy(codes[i], &code[start]);
}
free(code);
}
// 打印哈夫曼编码
void printHuffmanCode(struct HuffmanNode* nodes, char** codes, int n) {
int i;
printf("哈夫曼编码为:\n");
for (i = 0; i < n; i++) {
printf("%c:%s\n", i + 'A', codes[i]);
}
}
// 哈夫曼译码
void huffmanDecode(struct HuffmanNode* nodes, char** codes, int n) {
char* input = (char*)malloc(100 * sizeof(char)); // 存储输入的二进制编码
printf("\n请输入二进制编码:");
scanf("%s", input);
printf("哈夫曼译码结果为:");
int index = 2 * n - 2; // 从根节点开始
for (int i = 0; input[i] != '\0'; i++) {
if (input[i] == '0') {
index = nodes[index].left; // 左孩子节点
} else if (input[i] == '1') {
index = nodes[index].right; // 右孩子节点
}
// 到达叶子节点,输出对应的字符
if (nodes[index].left == -1 && nodes[index].right == -1) {
printf("%c", index + 'A');
index = 2 * n - 2; // 重新从根节点开始匹配
}
}
free(input);
}
int main() {
int n = 8; // 节点数
struct HuffmanNode* nodes = (struct HuffmanNode*)malloc((2 * n - 1) * sizeof(struct HuffmanNode));
char** codes = (char**)malloc(n * sizeof(char*));
buildHuffmanTree(nodes, n);
generateHuffmanCode(nodes, n, codes);
printHuffmanCode(nodes, codes, n);
huffmanDecode(nodes, codes, n);
// 释放内存
for (int i = 0; i < n; i++) {
free(codes[i]);
}
free(codes);
free(nodes);
return 0;
}
运行结果:
请输入节点 A 的权值:5
请输入节点 B 的权值:29
请输入节点 C 的权值:7
请输入节点 D 的权值:8
请输入节点 E 的权值:14
请输入节点 F 的权值:23
请输入节点 G 的权值:3
请输入节点 H 的权值:11
哈夫曼编码为:
A:110
B:0
C:111
D:100
E:10
F:101
G:1100
H:1101
请输入二进制编码:1001011110010110
哈夫曼译码结果为:DEBACHF
在以上代码中,我们首先定义了struct HuffmanNode结构体来表示哈夫曼树的节点。然后,使用buildHuffmanTree函数来构建哈夫曼树,并从键盘输入各个节点的权值。接下来,使用generateHuffmanCode函数生成哈夫曼编码,并使用printHuffmanCode函数打印哈夫曼编码表。
最后,使用huffmanDecode函数实现哈夫曼译码。在译码过程中,我们通过输入二进制编码,从根节点开始逐步匹配到叶子节点,并输出对应的字符。
运行结果显示了生成的哈夫曼编码表以及对输入二进制编码进行译码后得到的结果。
请注意,此代码假设输入的二进制编码是有效的,并且没有错误或歧义。如果存在错误或歧义,代码需要进行适当的错误处理。