c语言哈夫曼树压缩解压文件
时间: 2023-12-20 20:05:15 浏览: 153
哈夫曼树实现文件解压缩
4星 · 用户满意度95%
以下是C语言实现哈夫曼树压缩解压文件的步骤和代码示例:
1. 定义哈夫曼树节点结构体和哈夫曼编码表结构体
```c
typedef struct {
unsigned int weight; // 字符权重
unsigned int parent, lchild, rchild; // 父节点、左子节点、右子节点
} HTNode, *HuffmanTree;
typedef char** HuffmanCode; // 动态分配数组存储哈夫曼编码表
```
2. 定义哈夫曼树相关函数
```c
// 选择权值最小的两个节点
void select(HuffmanTree HT, int n, int* s1, int* s2);
// 建立哈夫曼树
void createHuffmanTree(HuffmanTree* HT, int n);
// 生成哈夫曼编码
void createHuffmanCode(HuffmanTree HT, HuffmanCode* HC, int n);
// 压缩文件
void compressFile(char* inputFile, char* outputFile, HuffmanCode HC);
// 解压文件
void decompressFile(char* inputFile, char* outputFile, HuffmanTree HT, int fileLength);
```
3. 实现哈夫曼树相关函数
```c
// 选择权值最小的两个节点
void select(HuffmanTree HT, int n, int* s1, int* s2) {
int i;
unsigned int min1 = UINT_MAX, min2 = UINT_MAX; // 初始化为最大值
for (i = 1; i <= n; i++) {
if (HT[i].parent == 0) { // 只考虑未被选中的节点
if (HT[i].weight < min1) {
min2 = min1;
*s2 = *s1;
min1 = HT[i].weight;
*s1 = i;
}
else if (HT[i].weight < min2) {
min2 = HT[i].weight;
*s2 = i;
}
}
}
}
// 建立哈夫曼树
void createHuffmanTree(HuffmanTree* HT, int n) {
if (n <= 1) {
return;
}
int m = 2 * n - 1; // 哈夫曼树总节点数
*HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode)); // 动态分配数组存储哈夫曼树
int i;
for (i = 1; i <= n; i++) { // 初始化前n个节点
(*HT)[i].weight = 0;
(*HT)[i].parent = 0;
(*HT)[i].lchild = 0;
(*HT)[i].rchild = 0;
}
for (i = n + 1; i <= m; i++) { // 初始化后m-n个节点
(*HT)[i].weight = 0;
(*HT)[i].parent = 0;
(*HT)[i].lchild = 0;
(*HT)[i].rchild = 0;
}
for (i = 1; i <= n; i++) { // 输入前n个节点的权值
scanf("%d", &((*HT)[i].weight));
}
int s1, s2;
for (i = n + 1; i <= m; i++) { // 构造哈夫曼树
select(*HT, i - 1, &s1, &s2);
(*HT)[s1].parent = i;
(*HT)[s2].parent = i;
(*HT)[i].lchild = s1;
(*HT)[i].rchild = s2;
(*HT)[i].weight = (*HT)[s1].weight + (*HT)[s2].weight;
}
}
// 生成哈夫曼编码
void createHuffmanCode(HuffmanTree HT, HuffmanCode* HC, int n) {
*HC = (HuffmanCode)malloc((n + 1) * sizeof(char*)); // 动态分配数组存储哈夫曼编码表
char* code = (char*)malloc(n * sizeof(char)); // 分配临时存储编码的空间
code[n - 1] = '\0'; // 编码结束符
int i;
for (i = 1; i <= n; i++) { // 逐个字符求哈夫曼编码
int start = n - 1; // 编码结束符位置
int c = i; // 从叶子节点开始向上回溯
int f = HT[i].parent;
while (f != 0) { // 直到回溯到根节点
if (HT[f].lchild == c) {
code[--start] = '0';
}
else {
code[--start] = '1';
}
c = f;
f = HT[f].parent;
}
(*HC)[i] = (char*)malloc((n - start) * sizeof(char)); // 分配存储编码的空间
strcpy((*HC)[i], &code[start]); // 复制编码
}
free(code); // 释放临时存储编码的空间
}
// 压缩文件
void compressFile(char* inputFile, char* outputFile, HuffmanCode HC) {
FILE* in = fopen(inputFile, "rb"); // 以二进制方式打开输入文件
FILE* out = fopen(outputFile, "wb"); // 以二进制方式打开输出文件
unsigned char c; // 读入的字符
unsigned char buffer = 0; // 缓存区
int count = 0; // 缓存区中剩余的位数
while (fread(&c, sizeof(unsigned char), 1, in) == 1) { // 逐个字符读入
char* code = HC[c]; // 获取哈夫曼编码
while (*code != '\0') { // 逐位写入缓存区
if (*code == '1') {
buffer = buffer | (1 << count);
}
count++;
if (count == 8) { // 缓存区满了,写入输出文件
fwrite(&buffer, sizeof(unsigned char), 1, out);
buffer = 0;
count = 0;
}
code++;
}
}
if (count > 0) { // 最后一个字节不足8位,补0写入输出文件
buffer = buffer << (8 - count);
fwrite(&buffer, sizeof(unsigned char), 1, out);
}
fclose(in); // 关闭输入文件
fclose(out); // 关闭输出文件
}
// 解压文件
void decompressFile(char* inputFile, char* outputFile, HuffmanTree HT, int fileLength) {
FILE* in = fopen(inputFile, "rb"); // 以二进制方式打开输入文件
FILE* out = fopen(outputFile, "wb"); // 以二进制方式打开输出文件
unsigned char c; // 读入的字符
int p = 2 * fileLength - 1; // 指向哈夫曼树根节点
while (fread(&c, sizeof(unsigned char), 1, in) == 1) { // 逐个字节读入
int i;
for (i = 0; i < 8; i++) { // 逐位解码
if ((c & (1 << (7 - i))) == 0) {
p = HT[p].lchild;
}
else {
p = HT[p].rchild;
}
if (HT[p].lchild == 0 && HT[p].rchild == 0) { // 到达叶子节点,写入输出文件
fwrite(&(HT[p].weight), sizeof(unsigned char), 1, out);
p = 2 * fileLength - 1; // 指向哈夫曼树根节点
}
}
}
fclose(in); // 关闭输入文件
fclose(out); // 关闭输出文件
}
```
4. 调用函数进行压缩解压文件
```c
int main() {
HuffmanTree HT;
HuffmanCode HC;
int n = 256; // 字符集大小
createHuffmanTree(&HT, n); // 建立哈夫曼树
createHuffmanCode(HT, &HC, n); // 生成哈夫曼编码
compressFile("input.txt", "output.dat", HC); // 压缩文件
decompressFile("output.dat", "output.txt", HT, n); // 解压文件
return 0;
}
```
阅读全文