哈夫曼编码压缩文件c语言代码
时间: 2024-06-03 16:05:53 浏览: 123
用哈夫曼编码实现文件压缩
哈夫曼编码是一种基于字符出现频率的压缩算法,它可以将一些出现频率较高的字符用较短的编码表示,从而实现对数据的压缩。下面是哈夫曼编码压缩文件的C语言代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义哈夫曼树节点结构体
typedef struct huffman_node {
unsigned char data; // 字符数据
unsigned int freq; // 字符出现频率
struct huffman_node *left, *right; // 左右子节点指针
} huffman_node;
// 定义哈夫曼编码结构体
typedef struct huffman_code {
unsigned char data; // 字符数据
unsigned int freq; // 字符出现频率
char *code; // 字符编码
} huffman_code;
// 统计字符出现频率,返回一个包含256个元素的数组,数组下标为字符ASCII码值,数组元素为该字符出现的次数
unsigned int *count_freq(FILE *fp) {
unsigned int *freq = (unsigned int *)calloc(256, sizeof(unsigned int));
unsigned char c;
while(fread(&c, sizeof(char), 1, fp)) {
freq[c]++;
}
return freq;
}
// 创建哈夫曼树,返回树的根节点指针
huffman_node *create_tree(unsigned int *freq) {
int i, j, min1, min2;
huffman_node *nodes = (huffman_node *)malloc(256 * sizeof(huffman_node));
for(i = 0, j = 0; i < 256; i++) {
if(freq[i] > 0) {
nodes[j].data = i;
nodes[j].freq = freq[i];
nodes[j].left = nodes[j].right = NULL;
j++;
}
}
int n = j;
for(i = 0; i < n - 1; i++) {
min1 = min2 = -1;
for(j = 0; j < n + i; j++) {
if(nodes[j].freq > 0) {
if(min1 == -1 || nodes[j].freq < nodes[min1].freq) {
min2 = min1;
min1 = j;
} else if(min2 == -1 || nodes[j].freq < nodes[min2].freq) {
min2 = j;
}
}
}
nodes[n + i].data = 0;
nodes[n + i].freq = nodes[min1].freq + nodes[min2].freq;
nodes[n + i].left = &nodes[min1];
nodes[n + i].right = &nodes[min2];
nodes[min1].freq = 0;
nodes[min2].freq = 0;
}
return &nodes[n + i - 1];
}
// 递归生成哈夫曼编码,并将结果保存到huffman_code数组中,返回哈夫曼编码数组的长度
int generate_code(huffman_node *node, char *code, huffman_code *hcode, int index) {
if(node->left == NULL && node->right == NULL) {
hcode[index].data = node->data;
hcode[index].freq = node->freq;
hcode[index].code = (char *)malloc(strlen(code) + 1);
strcpy(hcode[index].code, code);
return index + 1;
} else {
int left_index = generate_code(node->left, strcat(code, "0"), hcode, index);
code[strlen(code) - 1] = '\0';
int right_index = generate_code(node->right, strcat(code, "1"), hcode, left_index);
code[strlen(code) - 1] = '\0';
return right_index;
}
}
// 将哈夫曼编码写入文件
void write_code(FILE *fp, huffman_code *hcode, int len) {
fwrite(&len, sizeof(int), 1, fp);
int i, j, n;
for(i = 0; i < len; i++) {
fwrite(&hcode[i].data, sizeof(char), 1, fp);
fwrite(&hcode[i].freq, sizeof(int), 1, fp);
n = strlen(hcode[i].code);
fwrite(&n, sizeof(int), 1, fp);
for(j = 0; j < n; j++) {
fwrite(&hcode[i].code[j], sizeof(char), 1, fp);
}
}
}
// 将文件内容按照哈夫曼编码压缩,并写入文件
void compress_file(FILE *src_fp, FILE *dst_fp, huffman_code *hcode, int len) {
unsigned char c;
char *code;
int i, j, n;
while(fread(&c, sizeof(char), 1, src_fp)) {
for(i = 0; i < len; i++) {
if(hcode[i].data == c) {
code = hcode[i].code;
n = strlen(code);
for(j = 0; j < n; j++) {
if(code[j] == '0') {
fwrite("0", sizeof(char), 1, dst_fp);
} else {
fwrite("1", sizeof(char), 1, dst_fp);
}
}
break;
}
}
}
}
int main(int argc, char **argv) {
if(argc != 3) {
printf("Usage: %s source_file target_file\n", argv);
exit(1);
}
FILE *src_fp = fopen(argv, "rb");
if(src_fp == NULL) {
printf("Open source file failed!\n");
exit(1);
}
FILE *dst_fp = fopen(argv, "wb");
if(dst_fp == NULL) {
printf("Open target file failed!\n");
exit(1);
}
unsigned int *freq = count_freq(src_fp);
rewind(src_fp);
huffman_node *root = create_tree(freq);
huffman_code *hcode = (huffman_code *)malloc(256 * sizeof(huffman_code));
generate_code(root, "", hcode, 0);
write_code(dst_fp, hcode, 256);
compress_file(src_fp, dst_fp, hcode, 256);
fclose(src_fp);
fclose(dst_fp);
return 0;
}
```
阅读全文