给定权值{A:5,B:29,C:7,D:8,E:14,F:23,G:3,H:11}建立哈夫曼树,输出哈夫曼编码;对上述给定的哈夫曼树及得到的哈夫曼编码,试输入一串二进制编码,输出它的哈夫曼译码。
要求:将哈夫曼树的结构定义为一个一维数组,每个元素含有四顶:权值、双亲、左孩、右孩。权值由键盘输入;二进制编码时,往左走编码为0,往右走编码为1 ;译码就是将输入的编码还原成对应的字符
希望注释可以多一点,感谢
引用chatgpt部分指引作答:
以下是用C语言(使用Code::Blocks)实现的哈夫曼树代码和运行结果。代码中包含了详细的注释来解释每个步骤的目的和功能。
#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函数实现哈夫曼译码。在译码过程中,我们通过输入二进制编码,从根节点开始逐步匹配到叶子节点,并输出对应的字符。
运行结果显示了生成的哈夫曼编码表以及对输入二进制编码进行译码后得到的结果。
请注意,此代码假设输入的二进制编码是有效的,并且没有错误或歧义。如果存在错误或歧义,代码需要进行适当的错误处理。
超多注释
好的,以下是完整的C语言代码实现:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_N 50
typedef struct{
int weight; // 权值
int parent; // 双亲节点
int left; // 左孩子节点
int right; // 右孩子节点
} HTNode;
typedef char *HCode;
// 构建哈夫曼树
void CreateHuffmanTree(HTNode huffTree[], int n);
// 根据哈夫曼树求哈夫曼编码
void HuffmanEncoding(HTNode huffTree[], HCode huffCode[], int n);
// 哈夫曼编码解码
void HuffmanDecoding(HTNode huffTree[], HCode huffCode[], char input[], char output[]);
int main()
{
// 定义字符集合
char chars[] = "ABCDEFGH";
// 定义字符集合的权值
int weights[] = {5, 29, 7, 8, 14, 23, 3, 11};
// 定义字符集合长度
int n = sizeof(chars) / sizeof(chars[0]);
// 定义哈夫曼树
HTNode huffTree[2 * MAX_N - 1];
// 定义哈夫曼编码
HCode huffCode[MAX_N];
// 构建哈夫曼树
CreateHuffmanTree(huffTree, n);
// 根据哈夫曼树求哈夫曼编码
HuffmanEncoding(huffTree, huffCode, n);
// 输出哈夫曼编码
printf("Huffman Codes:\n");
for(int i = 0; i < n; i++)
{
printf("%c: %s\n", chars[i], huffCode[i]);
}
// 定义输入输出字符串
char input[MAX_N];
char output[MAX_N];
// 输入查询的哈夫曼编码
printf("Enter the Huffman Code to be decoded:\n");
scanf("%s", input);
// 哈夫曼编码解码
HuffmanDecoding(huffTree, huffCode, input, output);
// 输出解码结果
printf("Huffman Decoded String: %s\n", output);
return 0;
}
// 构建哈夫曼树
void CreateHuffmanTree(HTNode huffTree[], int n)
{
// 初始化哈夫曼树,将前n个叶子节点的权值初始化为字符集合对应的权值
for(int i = 0; i < n; i++)
{
huffTree[i].weight = huffTree[i].left = huffTree[i].right = huffTree[i].parent = -1;
huffTree[i].weight = i < n ? weights[i] : 0;
}
// 构建哈夫曼树
for(int i = n; i < 2 * n - 1; i++)
{
int min1 = -1;
int min2 = -1;
for(int j = 0; j <= i - 1; j++)
{
if(huffTree[j].parent < 0)
{
if(min1 == -1)
min1 = j;
else if(min2 == -1)
min2 = j;
else if(huffTree[j].weight < huffTree[min1].weight)
{
min2 = min1;
min1 = j;
}
else if(huffTree[j].weight < huffTree[min2].weight)
{
min2 = j;
}
}
}
huffTree[min1].parent = i;
huffTree[min2].parent = i;
huffTree[i].left = min1;
huffTree[i].right = min2;
huffTree[i].weight = huffTree[min1].weight + huffTree[min2].weight;
}
}
// 根据哈夫曼树求哈夫曼编码
void HuffmanEncoding(HTNode huffTree[], HCode huffCode[], int n)
{
// 分配存放哈夫曼编码的缓存区
char *code = (char*)malloc(sizeof(char) * n);
code[n - 1] = '\0';
// 遍历每一个叶子节点,求出其哈夫曼编码
for(int i = 0; i < n; i++)
{
int curr = i;
int parent = huffTree[curr].parent;
int k = n - 1;
// 表示如果当前节点不是根节点
while(parent >= 0)
{
// 如果当前节点是其父亲节点的左孩子
if(huffTree[parent].left == curr)
code[--k] = '0';
else
code[--k] = '1';
curr = parent;
parent = huffTree[curr].parent;
}
huffCode[i] = (char*)malloc(sizeof(char) * (n - k));
strcpy(huffCode[i], code + k);
}
free(code);
}
以下是我刚实现的代码,你看可以不
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
struct node {
int weight; // 权值
int parent; // 双亲
int lchild; // 左孩子
int rchild; // 右孩子
};
struct node huff[MAX * 2]; // 哈夫曼树
int n; // 权值个数
void input() {
printf("请输入权值个数:");
scanf("%d", &n);
for (int i = 0; i < n; i++) {
printf("请输入第%d个权值:", i + 1);
scanf("%d", &huff[i].weight);
huff[i].parent = -1;
huff[i].lchild = -1;
huff[i].rchild = -1;
}
}
void sort() {
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (huff[j].weight > huff[j + 1].weight) {
struct node temp = huff[j];
huff[j] = huff[j + 1];
huff[j + 1] = temp;
}
}
}
}
void create() {
for (int i = n; i < 2 * n - 1; i++) {
int min1 = -1, min2 = -1;
for (int j = 0; j < i; j++) {
if (huff[j].parent == -1) { // 如果该节点没有双亲,则说明它还没有被加入哈夫曼树中
if (min1 == -1) { // 如果min1还没有被赋值,则直接赋值为j
min1 = j;
} else if (min2 == -1) { // 如果min2还没有被赋值,则直接赋值为j
min2 = j;
} else if (huff[j].weight < huff[min1].weight) { // 如果j的权值小于min1的权值,则将min2赋值为min1,将min1赋值为j
min2 = min1;
min1 = j;
} else if (huff[j].weight < huff[min2].weight) { // 如果j的权值小于min2的权值,则将min2赋值为j
min2 = j;
}
}
}
huff[min1].parent = i;
huff[min2].parent = i;
huff[i].lchild = min1;
huff[i].rchild = min2;
huff[i].weight = huff[min1].weight + huff[min2].weight;
}
}
void encode() {
char code[MAX];
for (int i = 0; i < n; i++) {
int child = i, parent = huff[child].parent;
while (parent != -1) { // 如果该节点有双亲,则说明它还没有到达哈夫曼树的根节点
if (huff[parent].lchild == child) code[--child] = '0'; // 如果该节点是其双亲的左孩子,则在编码中添加0
else code[--child] = '1'; // 如果该节点是其双亲的右孩子,则在编码中添加1
child = parent;
parent = huff[child].parent;
}
printf("%c的哈夫曼编码为:", 'A' + i);
puts(&code[child]);
}
}
void decode() {
char code[MAX];
printf("请输入二进制编码:");
scanf("%s", code);
int p = 2 * n - 2;
for (int i = 0; code[i]; i++) { // 遍历二进制编码中的每一位
if (code[i] == '0') p = huff[p].lchild;
else p = huff[p].rchild;
if (huff[p].lchild == -1 && huff[p].rchild == -1) {
printf("%c", 'A' + p);
p = 2 * n - 2;
}
}
}
int main() {
input();
sort();
create();
encode();
decode();
return 0;
}
实现哈夫曼树的关键在于构建哈夫曼树,我们可以按照以下步骤进行构建:
将给定的节点按照权值从小到大排序。
从剩余节点中选取两个权值最小的节点作为新节点的左右孩子,将两个节点的权值相加作为新节点的权值,将新节点插入排序好的节点列表中。
重复第 2 步,直到只剩下一个节点,即为哈夫曼树的根节点。过程中保存每个节点的双亲、左孩子、右孩子等信息。
在建立好哈夫曼树后,我们可以使用递归方式生成哈夫曼编码。哈夫曼编码的生成规则为:在左边走为0,在右边走为1,所以我们可以采用前缀码的思路,从根节点开始遍历树,在向左或向右走的过程中,将路径上经过的方向编码记录下来。经过左节点编码为0,经过右节点编码为1,最终到达叶子节点的时候便得到了对应的哈夫曼编码。
以下是带注释的示例代码,实现了对给定权值建立哈夫曼树的功能,并输出各个节点的哈夫曼编码。代码中树的结构被定义为一个一维数组,包括权值、双亲、左孩和右孩等信息。
class Node(object):
def __init__(self, weight, parent, left_child, right_child):
self.weight = weight # 权值
self.parent = parent # 双亲
self.left_child = left_child # 左孩子
self.right_child = right_child # 右孩子
self.huffman_code = '' # 哈夫曼编码
def get_weight(self):
return self.weight
def get_parent(self):
return self.parent
def get_left_child(self):
return self.left_child
def get_right_child(self):
return self.right_child
def get_huffman_code(self):
return self.huffman_code
def set_weight(self, weight):
self.weight = weight
def set_parent(self, parent):
self.parent = parent
def set_left_child(self, left_child):
self.left_child = left_child
def set_right_child(self, right_child):
self.right_child = right_child
def set_huffman_code(self, huffman_code):
self.huffman_code = huffman_code
def create_huffman_tree(nodes, n):
"""
根据节点集合按照哈夫曼算法构建哈夫曼树
"""
for i in range(n-1):
# 每次选出权值最小的两个节点进行合并
min1 = min2 = 2**30
x1 = x2 = 0
for j in range(n+i):
if nodes[j].get_parent() == -1:
# 不在树中的节点才需要参与合并
if nodes[j].get_weight() < min1:
min2, x2 = min1, x1
min1, x1 = nodes[j].get_weight(), j
elif nodes[j].get_weight() < min2:
min2, x2 = nodes[j].get_weight(), j
nodes[x1].set_parent(n+i)
nodes[x2].set_parent(n+i)
nodes[n+i].set_weight(min1+min2)
nodes[n+i].set_left_child(x1)
nodes[n+i].set_right_child(x2)
def generate_huffman_code(nodes, leaf_idx):
"""
递归生成哈夫曼编码
"""
if nodes[leaf_idx].get_parent() == -1:
return
else:
generate_huffman_code(nodes, nodes[leaf_idx].get_parent())
if nodes[nodes[leaf_idx].get_parent()].get_left_child() == leaf_idx:
nodes[leaf_idx].set_huffman_code(nodes[nodes[leaf
实现哈夫曼树的关键在于构建哈夫曼树,我们可以按照以下步骤进行构建:
1. 将给定的节点按照权值从小到大排序。
2. 从剩余节点中选取两个权值最小的节点作为新节点的左右孩子,将两个节点的权值相加作为新节点的权值,将新节点插入排序好的节点列表中。
3. 重复第 2 步,直到只剩下一个节点,即为哈夫曼树的根节点。过程中保存每个节点的双亲、左孩子、右孩子等信息。
在建立好哈夫曼树后,我们可以使用递归方式生成哈夫曼编码。哈夫曼编码的生成规则为:在左边走为0,在右边走为1,所以我们可以采用前缀码的思路,从根节点开始遍历树,在向左或向右走的过程中,将路径上经过的方向编码记录下来。经过左节点编码为0,经过右节点编码为1,最终到达叶子节点的时候便得到了对应的哈夫曼编码。
以下是带注释的示例代码,实现了对给定权值建立哈夫曼树的功能,并输出各个节点的哈夫曼编码。代码中树的结构被定义为一个一维数组,包括权值、双亲、左孩和右孩等信息。
```python
class Node(object):
def __init__(self, weight, parent, left_child, right_child):
self.weight = weight # 权值
self.parent = parent # 双亲
self.left_child = left_child # 左孩子
self.right_child = right_child # 右孩子
self.huffman_code = '' # 哈夫曼编码
def get_weight(self):
return self.weight
def get_parent(self):
return self.parent
def get_left_child(self):
return self.left_child
def get_right_child(self):
return self.right_child
def get_huffman_code(self):
return self.huffman_code
def set_weight(self, weight):
self.weight = weight
def set_parent(self, parent):
self.parent = parent
def set_left_child(self, left_child):
self.left_child = left_child
def set_right_child(self, right_child):
self.right_child = right_child
def set_huffman_code(self, huffman_code):
self.huffman_code = huffman_code
def create_huffman_tree(nodes, n):
"""
根据节点集合按照哈夫曼算法构建哈夫曼树
"""
for i in range(n-1):
# 每次选出权值最小的两个节点进行合并
min1 = min2 = 2**30
x1 = x2 = 0
for j in range(n+i):
if nodes[j].get_parent() == -1:
# 不在树中的节点才需要参与合并
if nodes[j].get_weight() < min1:
min2, x2 = min1, x1
min1, x1 = nodes[j].get_weight(), j
elif nodes[j].get_weight() < min2:
min2, x2 = nodes[j].get_weight(), j
nodes[x1].set_parent(n+i)
nodes[x2].set_parent(n+i)
nodes[n+i].set_weight(min1+min2)
nodes[n+i].set_left_child(x1)
nodes[n+i].set_right_child(x2)
def generate_huffman_code(nodes, leaf_idx):
"""
递归生成哈夫曼编码
"""
if nodes[leaf_idx].get_parent() == -1:
return
else:
generate_huffman_code(nodes, nodes[leaf_idx].get_parent())
if nodes[nodes[leaf_idx].get_parent()].get_left_child() == leaf_idx:
nodes[leaf_idx].set_huffman_code(nodes[nodes[leaf
不知道你这个问题是否已经解决, 如果还没有解决的话: