设计实现一个基于哈夫曼算法的压缩软件,统计文件中各字符出现的频次,设计哈夫曼编码,实现文件的压缩及解压缩。(要求C语言详细代码)
时间: 2024-02-03 14:12:28 浏览: 119
哈夫曼压缩与解压文件课程设计(代码+实习报告)
4星 · 用户满意度95%
以下是C语言实现的哈夫曼压缩/解压缩程序:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
// 哈夫曼树节点结构体
typedef struct huffman_node {
unsigned char c; // 字符
int freq; // 频率
struct huffman_node *left, *right; // 左右子节点指针
} huffman_node;
// 哈夫曼编码结构体
typedef struct huffman_code {
unsigned char c; // 字符
char *code; // 编码
} huffman_code;
// 统计字符频率
void calc_freq(FILE *fp, int freq[]) {
int c;
while ((c = fgetc(fp)) != EOF) {
freq[c]++;
}
}
// 创建哈夫曼节点
huffman_node *create_huffman_node(unsigned char c, int freq) {
huffman_node *node = (huffman_node *)malloc(sizeof(huffman_node));
node->c = c;
node->freq = freq;
node->left = node->right = NULL;
return node;
}
// 比较函数
int compare(const void *a, const void *b) {
const huffman_node *x = *(const huffman_node **)a;
const huffman_node *y = *(const huffman_node **)b;
return x->freq - y->freq;
}
// 构建哈夫曼树
huffman_node *build_huffman_tree(int freq[]) {
huffman_node *nodes[256];
int i, j, n = 0;
for (i = 0; i < 256; i++) {
if (freq[i] > 0) {
nodes[n++] = create_huffman_node(i, freq[i]);
}
}
while (n > 1) {
qsort(nodes, n, sizeof(huffman_node *), compare);
huffman_node *node = create_huffman_node(0, nodes[0]->freq + nodes[1]->freq);
node->left = nodes[0];
node->right = nodes[1];
nodes[0] = node;
nodes[1] = nodes[--n];
}
return nodes[0];
}
// 递归获取编码
void get_codes(huffman_node *node, char *code, int len, huffman_code *codes) {
if (node->left == NULL && node->right == NULL) {
codes[node->c].c = node->c;
codes[node->c].code = (char *)malloc(len + 1);
memcpy(codes[node->c].code, code, len);
codes[node->c].code[len] = 0;
return;
}
code[len] = '0';
get_codes(node->left, code, len + 1, codes);
code[len] = '1';
get_codes(node->right, code, len + 1, codes);
}
// 构建哈夫曼编码
huffman_code *build_huffman_code(huffman_node *root) {
char code[256];
huffman_code *codes = (huffman_code *)malloc(sizeof(huffman_code) * 256);
memset(codes, 0, sizeof(huffman_code) * 256);
get_codes(root, code, 0, codes);
return codes;
}
// 压缩文件
void compress(const char *in_filename, const char *out_filename, huffman_code *codes, int freq[]) {
FILE *in_file = fopen(in_filename, "rb");
FILE *out_file = fopen(out_filename, "wb");
fwrite(freq, sizeof(int), 256, out_file);
int c, bit = 0, byte = 0;
unsigned char buf = 0;
while ((c = fgetc(in_file)) != EOF) {
char *code = codes[c].code;
while (*code) {
if (*code++ == '1') {
buf |= (1 << bit);
}
if (++bit == 8) {
fputc(buf, out_file);
buf = 0;
bit = 0;
byte++;
}
}
}
if (bit > 0) {
fputc(buf, out_file);
byte++;
}
fclose(in_file);
fclose(out_file);
printf("Compressed %s (%d bytes) => %s (%d bytes)\n", in_filename, ftell(in_file), out_filename, byte);
}
// 解压缩文件
void decompress(const char *in_filename, const char *out_filename, huffman_node *root) {
FILE *in_file = fopen(in_filename, "rb");
FILE *out_file = fopen(out_filename, "wb");
int freq[256];
fread(freq, sizeof(int), 256, in_file);
huffman_node *nodes[256];
int i, n = 0;
for (i = 0; i < 256; i++) {
if (freq[i] > 0) {
nodes[n++] = create_huffman_node(i, freq[i]);
}
}
while (n > 1) {
qsort(nodes, n, sizeof(huffman_node *), compare);
huffman_node *node = create_huffman_node(0, nodes[0]->freq + nodes[1]->freq);
node->left = nodes[0];
node->right = nodes[1];
nodes[0] = node;
nodes[1] = nodes[--n];
}
huffman_node *node = nodes[0];
int c, bit = 0;
while ((c = fgetc(in_file)) != EOF) {
for (bit = 7; bit >= 0; bit--) {
if (node->left == NULL && node->right == NULL) {
fputc(node->c, out_file);
node = nodes[0];
}
if ((c >> bit) & 1) {
node = node->right;
} else {
node = node->left;
}
}
}
fclose(in_file);
fclose(out_file);
printf("Decompressed %s => %s\n", in_filename, out_filename);
}
int main() {
int freq[256] = {0};
calc_freq(fopen("input.txt", "rb"), freq);
huffman_node *root = build_huffman_tree(freq);
huffman_code *codes = build_huffman_code(root);
compress("input.txt", "output.bin", codes, freq);
decompress("output.bin", "output.txt", root);
return 0;
}
```
该程序会将输入文件压缩成二进制文件,以及将压缩后的二进制文件解压缩成文本文件。在程序中,我们首先通过 `calc_freq` 函数统计文件中各字符出现的频次,然后通过 `build_huffman_tree` 函数构建哈夫曼树,并通过 `build_huffman_code` 函数得到每个字符对应的哈夫曼编码。最后,通过 `compress` 函数将输入文件压缩成二进制文件,以及通过 `decompress` 函数将压缩后的二进制文件解压缩成文本文件。
该程序中使用了如下数据结构:
- `huffman_node`:哈夫曼树节点结构体。
- `huffman_code`:哈夫曼编码结构体。
通过这些数据结构,我们可以方便地表示哈夫曼树和哈夫曼编码。
阅读全文