利用C语言编写完整代码。具体要求为: 从键盘任意输入一个由英文字母带空格构成的文本字符串,例如“I like Learning datastructure course”,首先根据该字符串创建Huffman树,之后进行Huffman编码,然后把该字符串的Huffman编码结果向屏幕输出。能够利用前述的Huffman编码结果对某0-1码流进行解码得到字符串,并做详细注释
时间: 2024-03-07 21:46:46 浏览: 52
C语言实现Huffman树,Huffman编码
5星 · 资源好评率100%
好的,以下是代码实现:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义Huffman树的节点
typedef struct node{
char data; // 存储字符
int freq; // 存储频率
struct node *left, *right;
}Node;
// 定义Huffman编码的节点
typedef struct code{
char data; // 存储字符
char *code; // 存储编码
}Code;
// 定义Huffman编码的表
typedef struct table{
Code *codes;
int size;
}Table;
// 统计字符频率
int *getFrequency(char *str){
int *freq = (int *)calloc(128, sizeof(int)); // 初始化为0
char *p = str;
while(*p != '\0'){
freq[(int)(*p)]++; // 将字符的ASCII码作为数组下标
p++;
}
return freq;
}
// 创建Huffman树
Node *createHuffmanTree(int *freq){
Node *nodes[128]; // 存储节点的数组
int size = 0;
for(int i=0; i<128; i++){
if(freq[i] > 0){
Node *node = (Node *)malloc(sizeof(Node));
node->data = (char)i;
node->freq = freq[i];
node->left = NULL;
node->right = NULL;
nodes[size++] = node;
}
}
while(size > 1){
int i = 0;
int j = 1;
if(nodes[i]->freq > nodes[j]->freq){
i = 1;
j = 0;
}
for(int k=2; k<size; k++){
if(nodes[k]->freq < nodes[i]->freq){
j = i;
i = k;
}else if(nodes[k]->freq < nodes[j]->freq){
j = k;
}
}
Node *parent = (Node *)malloc(sizeof(Node));
parent->data = '\0';
parent->freq = nodes[i]->freq + nodes[j]->freq;
parent->left = nodes[i];
parent->right = nodes[j];
nodes[j] = parent;
nodes[i] = nodes[--size];
}
return nodes[0];
}
// 递归实现Huffman编码
void encode(Node *root, Table *table, char *code){
if(root->left == NULL && root->right == NULL){
Code *c = (Code *)malloc(sizeof(Code));
c->data = root->data;
c->code = strdup(code);
table->codes[table->size++] = *c;
}else{
char leftCode[strlen(code) + 2];
strcpy(leftCode, code);
strcat(leftCode, "0");
char rightCode[strlen(code) + 2];
strcpy(rightCode, code);
strcat(rightCode, "1");
encode(root->left, table, leftCode);
encode(root->right, table, rightCode);
}
}
// 将字符串编码为Huffman编码
char *encodeString(char *str, Table *table){
char *encodedStr = (char *)malloc(strlen(str) * 10); // 分配足够大的空间
char *p = str;
while(*p != '\0'){
for(int i=0; i<table->size; i++){
if(table->codes[i].data == *p){
strcat(encodedStr, table->codes[i].code);
break;
}
}
p++;
}
return encodedStr;
}
// 将Huffman编码解码为字符串
char *decodeString(char *encodedStr, Table *table){
char *decodedStr = (char *)malloc(strlen(encodedStr) + 1); // 分配空间
char *p = encodedStr;
int decodedIndex = 0;
while(*p != '\0'){
for(int i=0; i<table->size; i++){
if(strncmp(table->codes[i].code, p, strlen(table->codes[i].code)) == 0){
decodedStr[decodedIndex++] = table->codes[i].data;
p += strlen(table->codes[i].code);
break;
}
}
}
decodedStr[decodedIndex] = '\0';
return decodedStr;
}
int main(){
char str[1000];
printf("请输入由英文字母带空格构成的文本字符串:\n");
fgets(str, 1000, stdin); // 从键盘输入
str[strlen(str)-1] = '\0'; // 去掉换行符
int *freq = getFrequency(str);
Node *root = createHuffmanTree(freq);
Table *table = (Table *)malloc(sizeof(Table));
table->size = 0;
table->codes = (Code *)malloc(128 * sizeof(Code));
encode(root, table, "");
printf("Huffman编码结果为:\n");
char *encodedStr = encodeString(str, table);
printf("%s\n", encodedStr);
printf("Huffman解码结果为:\n");
char *decodedStr = decodeString(encodedStr, table);
printf("%s\n", decodedStr);
free(encodedStr);
free(decodedStr);
free(table->codes);
free(table);
free(freq);
return 0;
}
```
接下来是详细注释:
1. 定义了Huffman树的节点、编码节点和编码表的结构体,分别用于存储Huffman树的节点信息、Huffman编码的信息和Huffman编码的表。
```c
// 定义Huffman树的节点
typedef struct node{
char data; // 存储字符
int freq; // 存储频率
struct node *left, *right;
}Node;
// 定义Huffman编码的节点
typedef struct code{
char data; // 存储字符
char *code; // 存储编码
}Code;
// 定义Huffman编码的表
typedef struct table{
Code *codes;
int size;
}Table;
```
2. 实现了一个函数`getFrequency`,用于统计字符串中每个字符出现的频率。
```c
// 统计字符频率
int *getFrequency(char *str){
int *freq = (int *)calloc(128, sizeof(int)); // 初始化为0
char *p = str;
while(*p != '\0'){
freq[(int)(*p)]++; // 将字符的ASCII码作为数组下标
p++;
}
return freq;
}
```
3. 实现了一个函数`createHuffmanTree`,用于根据字符频率创建Huffman树。
```c
// 创建Huffman树
Node *createHuffmanTree(int *freq){
Node *nodes[128]; // 存储节点的数组
int size = 0;
for(int i=0; i<128; i++){
if(freq[i] > 0){
Node *node = (Node *)malloc(sizeof(Node));
node->data = (char)i;
node->freq = freq[i];
node->left = NULL;
node->right = NULL;
nodes[size++] = node;
}
}
while(size > 1){
int i = 0;
int j = 1;
if(nodes[i]->freq > nodes[j]->freq){
i = 1;
j = 0;
}
for(int k=2; k<size; k++){
if(nodes[k]->freq < nodes[i]->freq){
j = i;
i = k;
}else if(nodes[k]->freq < nodes[j]->freq){
j = k;
}
}
Node *parent = (Node *)malloc(sizeof(Node));
parent->data = '\0';
parent->freq = nodes[i]->freq + nodes[j]->freq;
parent->left = nodes[i];
parent->right = nodes[j];
nodes[j] = parent;
nodes[i] = nodes[--size];
}
return nodes[0];
}
```
4. 实现了一个递归函数`encode`,用于对Huffman树的节点进行编码,并将编码结果存储在编码表中。
```c
// 递归实现Huffman编码
void encode(Node *root, Table *table, char *code){
if(root->left == NULL && root->right == NULL){
Code *c = (Code *)malloc(sizeof(Code));
c->data = root->data;
c->code = strdup(code);
table->codes[table->size++] = *c;
}else{
char leftCode[strlen(code) + 2];
strcpy(leftCode, code);
strcat(leftCode, "0");
char rightCode[strlen(code) + 2];
strcpy(rightCode, code);
strcat(rightCode, "1");
encode(root->left, table, leftCode);
encode(root->right, table, rightCode);
}
}
```
5. 实现了一个函数`encodeString`,用于将字符串编码为Huffman编码。
```c
// 将字符串编码为Huffman编码
char *encodeString(char *str, Table *table){
char *encodedStr = (char *)malloc(strlen(str) * 10); // 分配足够大的空间
char *p = str;
while(*p != '\0'){
for(int i=0; i<table->size; i++){
if(table->codes[i].data == *p){
strcat(encodedStr, table->codes[i].code);
break;
}
}
p++;
}
return encodedStr;
}
```
6. 实现了一个函数`decodeString`,用于将Huffman编码解码为字符串。
```c
// 将Huffman编码解码为字符串
char *decodeString(char *encodedStr, Table *table){
char *decodedStr = (char *)malloc(strlen(encodedStr) + 1); // 分配空间
char *p = encodedStr;
int decodedIndex = 0;
while(*p != '\0'){
for(int i=0; i<table->size; i++){
if(strncmp(table->codes[i].code, p, strlen(table->codes[i].code)) == 0){
decodedStr[decodedIndex++] = table->codes[i].data;
p += strlen(table->codes[i].code);
break;
}
}
}
decodedStr[decodedIndex] = '\0';
return decodedStr;
}
```
7. 在`main`函数中,先从键盘输入一个由英文字母带空格构成的文本字符串,然后按照前面实现的函数进行Huffman编码和解码,并将结果输出。
```c
int main(){
char str[1000];
printf("请输入由英文字母带空格构成的文本字符串:\n");
fgets(str, 1000, stdin); // 从键盘输入
str[strlen(str)-1] = '\0'; // 去掉换行符
int *freq = getFrequency(str);
Node *root = createHuffmanTree(freq);
Table *table = (Table *)malloc(sizeof(Table));
table->size = 0;
table->codes = (Code *)malloc(128 * sizeof(Code));
encode(root, table, "");
printf("Huffman编码结果为:\n");
char *encodedStr = encodeString(str, table);
printf("%s\n", encodedStr);
printf("Huffman解码结果为:\n");
char *decodedStr = decodeString(encodedStr, table);
printf("%s\n", decodedStr);
free(encodedStr);
free(decodedStr);
free(table->codes);
free(table);
free(freq);
return 0;
}
```
以上就是完整的代码实现和详细注释。
阅读全文