c语言编程实现哈夫曼编码和译码系统。 利用哈夫曼编码进行通讯可以大大提高信道利用率,缩短信息传输时间,降低传输成本,但是,这要求在发送端通过一个编码系统对待传数据进行预先编码;在接受端将传来的数据进行解码(复原)对于双工信道(即可以双向传输的信道),每端都要有一个完整的编/译码系统。请为这样的信息收发站写一个哈夫曼的编译码系统。 要求: 1)从终端读入字符集大小为n,及n个字符和n个权值,建立哈夫曼树,进行编码并且输出,并将它存于文件hfmtree中。 2)利用已建好的哈夫曼编码文件hfmtree,对存储于文件中的某正文进行编码。输出字符正文,再输出该文的二进制码。 3)对2)的编码进行译码,译码结果存储到文件中,并与编码前的文件对比。
时间: 2024-03-31 08:34:50 浏览: 97
好的,以下是一个C语言实现的哈夫曼编码和译码系统的基本思路:
1. 建立哈夫曼树:
(1)先定义节点结构体,包括字符、权值、左右子树指针等成员。
(2)读入字符集大小n、n个字符和n个权值,将每个字符和对应的权值存储在节点中。
(3)按照权值从小到大的顺序,将每个节点插入到一个初始为空的小根堆中。每次取出堆顶两个节点,合并为一个新节点,并将新节点插入堆中,直到堆中只剩下一个节点,这个节点就是哈夫曼树的根节点。
2. 进行编码:
(1)从根节点开始遍历哈夫曼树,如果遇到左子树就在编码序列的末尾添加0,遇到右子树就在编码序列的末尾添加1,直到叶子节点。
(2)将每个字符的编码序列存储在一个编码表中,可以使用一个数组存储,数组下标为字符的ASCII码值,对应的数组元素为该字符的编码序列。
(3)将建立好的哈夫曼编码表存储在hfmtree文件中。
3. 进行译码:
(1)读入编码文件,并按照每个字符的编码序列进行解码。从哈夫曼树的根节点开始遍历,如果遇到0就往左子树移动,遇到1就往右子树移动,直到遇到叶子节点。将叶子节点对应的字符存储下来,并回到根节点继续解码。
(2)将解码得到的字符存储在一个文件中,并与原来的文件进行比较,确认解码是否正确。
以上是哈夫曼编码和译码系统的基本思路,具体的实现还需要考虑很多细节问题,例如如何处理编码和译码过程中的边界情况等。如果你需要更详细的实现细节,可以提供更具体的问题,我会尽力解答。
相关问题
C语言:利用哈夫曼编码进行信息通讯可以大大提高信道的利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对待传输数据预先编码;在接受端将传来的数据进行译码。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的信息收发站编写一个哈夫曼码的编/译码系统。 基本要求:根据某字符文件统计字符出现频度,构造Huffman 树,编制Huffman 编码,并将给定字符文件编码,生成编码文件;再将给定编码文件解码,生成字符文件。(要求按二进制位表示编码) 测试数据:英文文件。 提高要求:用二进制表示编码,生成二进制的编码文件。
以下是基于C语言的哈夫曼编/译码实现代码,包括了基本要求和提高要求的实现:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 256 // 最大字符数
#define MAX_BIT 30 // 最大编码位数
// 哈夫曼树节点结构体
typedef struct TreeNode
{
char ch;
int weight;
struct TreeNode *left;
struct TreeNode *right;
} TreeNode;
// 哈夫曼编码结构体
typedef struct HuffmanCode
{
char ch; // 字符
int len; // 编码长度
char code[MAX_BIT]; // 编码字符串
} HuffmanCode;
// 统计字符出现频度
void count(char *filename, int *freq)
{
FILE *fp;
char ch;
fp = fopen(filename, "rb");
if (fp == NULL)
{
printf("文件打开失败!");
exit(1);
}
while ((ch = fgetc(fp)) != EOF)
{
freq[ch]++;
}
fclose(fp);
}
// 初始化哈夫曼树节点
TreeNode *initNode(char ch, int weight)
{
TreeNode *node = (TreeNode *)malloc(sizeof(TreeNode));
node->ch = ch;
node->weight = weight;
node->left = NULL;
node->right = NULL;
return node;
}
// 构建哈夫曼树
TreeNode *buildTree(int *freq)
{
int i, j, k;
TreeNode *node1, *node2, *node;
TreeNode **tree = (TreeNode **)malloc(MAX_SIZE * sizeof(TreeNode *));
for (i = 0, j = 0; i < MAX_SIZE; i++)
{
if (freq[i])
{
tree[j++] = initNode(i, freq[i]);
}
}
for (i = 0; i < j - 1; i++)
{
k = i + 1;
node1 = tree[i];
node2 = tree[k];
node = initNode('\0', node1->weight + node2->weight);
node->left = node1;
node->right = node2;
j++;
for (k = i + 2; k < j; k++)
{
tree[k - 1] = tree[k];
}
tree[j - 1] = node;
// 插入排序,保证树节点按权重递增排序
for (k = i + 1; k < j - 1 && node->weight > tree[k]->weight; k++)
{
tree[k - 1] = tree[k];
}
tree[k - 1] = node;
}
free(tree);
return node;
}
// 生成哈夫曼编码
void generateCode(TreeNode *root, HuffmanCode *code, int len, char *str)
{
if (root == NULL)
{
return;
}
if (root->left == NULL && root->right == NULL)
{
code[(int)root->ch].ch = root->ch;
code[(int)root->ch].len = len;
strcpy(code[(int)root->ch].code, str);
return;
}
str[len] = '0';
generateCode(root->left, code, len + 1, str);
str[len] = '1';
generateCode(root->right, code, len + 1, str);
}
// 哈夫曼编码压缩文件
void compress(char *filename, char *outname, HuffmanCode *code)
{
FILE *in, *out;
int i, j, count = 0;
char ch, buffer[MAX_BIT];
unsigned char byte = 0;
int len = 0;
in = fopen(filename, "rb");
out = fopen(outname, "wb");
while ((ch = fgetc(in)) != EOF)
{
for (i = 0; i < code[(int)ch].len; i++)
{
buffer[len++] = code[(int)ch].code[i];
if (len == 8)
{
len = 0;
for (j = 0; j < 8; j++)
{
byte <<= 1;
if (buffer[j] == '1')
{
byte |= 1;
}
}
fputc(byte, out);
byte = 0;
count++;
}
}
}
if (len > 0)
{
for (i = len; i < 8; i++)
{
buffer[i] = '0';
}
for (i = 0; i < 8; i++)
{
byte <<= 1;
if (buffer[i] == '1')
{
byte |= 1;
}
}
fputc(byte, out);
count++;
}
fclose(in);
fclose(out);
}
// 哈夫曼编码解压文件
void decompress(char *filename, char *outname, TreeNode *root)
{
FILE *in, *out;
char ch;
TreeNode *node = root;
in = fopen(filename, "rb");
out = fopen(outname, "wb");
while ((ch = fgetc(in)) != EOF)
{
int i;
for (i = 7; i >= 0; i--)
{
if (((ch >> i) & 1) == 1)
{
node = node->right;
}
else
{
node = node->left;
}
if (node->left == NULL && node->right == NULL)
{
fputc(node->ch, out);
node = root;
}
}
}
fclose(in);
fclose(out);
}
// 打印哈夫曼编码
void printCode(HuffmanCode *code)
{
int i;
printf("\n字符\t频度\t编码\n");
for (i = 0; i < MAX_SIZE; i++)
{
if (code[i].len > 0)
{
printf("%c\t%d\t%s\n", code[i].ch, code[i].len, code[i].code);
}
}
}
int main()
{
int i, freq[MAX_SIZE] = {0};
char filename[20], outname[20], str[MAX_BIT] = {'\0'};
HuffmanCode code[MAX_SIZE];
for (i = 0; i < MAX_SIZE; i++)
{
code[i].len = 0;
memset(code[i].code, 0, MAX_BIT);
}
printf("请输入需要压缩的文件名:");
scanf("%s", filename);
count(filename, freq);
TreeNode *root = buildTree(freq);
generateCode(root, code, 0, str);
printf("\n哈夫曼编码如下:\n");
printCode(code);
printf("\n请输入压缩后的文件名:");
scanf("%s", outname);
compress(filename, outname, code);
printf("\n文件压缩成功!\n");
printf("\n请输入需要解压的文件名:");
scanf("%s", outname);
decompress(outname, "output.txt", root);
printf("\n文件解压成功!\n");
return 0;
}
```
以上代码实现了基本要求和提高要求,可以根据输入的文件名进行哈夫曼编码压缩和解压缩操作,生成二进制的编码文件。
利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码,用C语言设计一个简单编码/译码系统,系统应具有如下功能: 1、接收原始数据。 从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树(输出哈弗曼树的存储结构的终态)。 2、编码 利用已建好的哈弗曼树,对输入的正文进行编码,存储编码结果。 3、译码 利用编码后的结果进行译码,存储译码结果。 4、打印编码规则 即字符与编码的一一对应关系。 5、打印哈夫曼树 将已创建的哈弗曼树输出到显示器上。
这是一个比较复杂的代码实现,我将提供一个基本的框架和思路。
1. 哈夫曼树的存储结构
我们可以使用二叉树来表示哈夫曼树。每个节点包含字符和权值,左右子树指针。在建立哈夫曼树的过程中,我们按照权值从小到大的顺序,将节点作为叶子节点插入二叉树。然后不断取出权值最小的两个节点,将它们合并成一个父节点,权值为两个子节点的权值之和,再将这个父节点插入二叉树中。重复这个过程,直到只剩下一个节点,即根节点。
2. 编码
编码的过程就是将原始数据转换为哈夫曼编码。我们可以使用一个哈希表来存储每个字符对应的编码,以便快速查找。在遍历哈夫曼树的过程中,每当走到一个左子树,就在编码序列末尾添加一个0,每当走到一个右子树,就在编码序列末尾添加一个1。当走到叶子节点时,就将整个编码序列存储起来,并将对应的字符和编码存入哈希表中。
3. 译码
译码的过程就是将哈夫曼编码转换为原始数据。我们可以使用一个指针指向哈夫曼树的根节点,然后遍历编码序列。每当遇到一个0,就让指针指向左子树;每当遇到一个1,就让指针指向右子树。当指针指向叶子节点时,就将对应的字符输出,并将指针重新指向根节点。
4. 打印编码规则
只需要遍历哈希表,输出每个字符和它对应的编码即可。
5. 打印哈夫曼树
可以使用递归遍历二叉树的方式,先输出右子树,再输出根节点,最后输出左子树。这样输出的结果就是从上到下,从右到左的顺序。
下面是一个基本的实现代码框架:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 哈夫曼树节点
typedef struct huffman_node {
char ch; // 字符
int weight; // 权值
struct huffman_node *lchild; // 左子树指针
struct huffman_node *rchild; // 右子树指针
} huffman_node;
// 哈夫曼编码节点
typedef struct huffman_code {
char ch; // 字符
char *code; // 编码
} huffman_code;
// 哈夫曼编码表
typedef struct huffman_table {
huffman_code *codes; // 编码数组
int n; // 字符集大小
} huffman_table;
// 从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树
huffman_node *create_huffman_tree(int n, char *chars, int *weights);
// 利用已建好的哈夫曼树,对输入的正文进行编码,存储编码结果
void huffman_encode(huffman_node *root, char *text, int len, huffman_table *table);
// 利用编码后的结果进行译码,存储译码结果
void huffman_decode(huffman_node *root, char *code, int len, char *text);
// 输出字符与编码的一一对应关系
void print_huffman_table(huffman_table *table);
// 将已创建的哈夫曼树输出到显示器上
void print_huffman_tree(huffman_node *root);
// 销毁哈夫曼树
void destroy_huffman_tree(huffman_node *root);
int main() {
// 读入字符集大小n,以及n个字符和n个权值
// ...
// 建立哈夫曼树
huffman_node *root = create_huffman_tree(n, chars, weights);
// 打印哈夫曼树
print_huffman_tree(root);
// 哈夫曼编码
huffman_table table;
huffman_encode(root, text, len, &table);
// 输出编码规则
print_huffman_table(&table);
// 哈夫曼译码
char *text2 = malloc(len + 1);
huffman_decode(root, table.codes[0].code, strlen(table.codes[0].code), text2);
printf("%s\n", text2);
// 销毁哈夫曼树
destroy_huffman_tree(root);
return 0;
}
huffman_node *create_huffman_tree(int n, char *chars, int *weights) {
// TODO: 实现建立哈夫曼树的代码
}
void huffman_encode(huffman_node *root, char *text, int len, huffman_table *table) {
// TODO: 实现哈夫曼编码的代码
}
void huffman_decode(huffman_node *root, char *code, int len, char *text) {
// TODO: 实现哈夫曼译码的代码
}
void print_huffman_table(huffman_table *table) {
// TODO: 实现打印编码规则的代码
}
void print_huffman_tree(huffman_node *root) {
// TODO: 实现打印哈夫曼树的代码
}
void destroy_huffman_tree(huffman_node *root) {
// TODO: 实现销毁哈夫曼树的代码
}
```
阅读全文