c 哈夫曼树文件压缩
时间: 2024-07-29 20:00:44 浏览: 54
哈夫曼树(Huffman Tree),也称为最优二叉树或霍夫曼编码,是一种用于数据压缩的算法。它是基于字符频率统计的一种无损压缩方法,常被应用于文本文件的存储和传输中,比如ASCII码就是一种简单的哈夫曼编码。
在C语言中,构建哈夫曼树的过程通常包含以下几个步骤:
1. **字符频率统计**:首先,分析输入文本中的每个字符及其出现的频率,创建一个频率表。
2. **构造初始节点**:将频率作为节点的权值,创建一个空的堆(通常是一个优先队列),并把所有字符和它们的频率放入堆中。
3. **构建树过程**:每次从堆顶取出两个权值最小的节点,合并成一个新的节点,新的节点的权值等于这两个子节点的权值之和,并将其回填到堆中。这个过程会持续直到只剩下一个节点,即为哈夫曼树的根节点。
4. **编码规则**:从根节点开始,对于原始字符,沿着树向下遍历,遇到分叉就向左走(代表0),向右走(代表1)。这样得到的一串“0”、“1”序列就是该字符的哈夫曼编码。
5. **文件压缩**:最后,用每个字符的哈夫曼编码替换其原始形式,因为频率低的字符对应的编码通常更短,所以整体上能有效减小文件大小。
相关问题
哈夫曼树文件压缩c语言
以下是使用C语言实现哈夫曼树文件压缩的步骤:
1.读取文件并统计每个字符出现的次数。
```c
FILE *fp;
char ch;
int freq[256] = {0};
fp = fopen("filename.txt", "r");
while((ch = fgetc(fp)) != EOF) {
freq[ch]++;
}
fclose(fp);
```
2.构建哈夫曼树。
```c
struct node {
int freq;
char data;
struct node *left, *right;
};
struct node *newNode(int freq, char data) {
struct node *temp = (struct node*)malloc(sizeof(struct node));
temp->freq = freq;
temp->data = data;
temp->left = temp->right = NULL;
return temp;
}
struct node *buildHuffmanTree(int freq[]) {
struct node *left, *right, *top;
priority_queue<node*, vector<node*>, compare> minHeap;
for(int i=0; i<256; i++) {
if(freq[i] != 0) {
minHeap.push(newNode(freq[i], i));
}
}
while(minHeap.size() != 1) {
left = minHeap.top();
minHeap.pop();
right = minHeap.top();
minHeap.pop();
top = newNode(left->freq + right->freq, '$');
top->left = left;
top->right = right;
minHeap.push(top);
}
return minHeap.top();
}
```
3.生成哈夫曼编码。
```c
void generateHuffmanCode(struct node *root, string str, unordered_map<char, string> &huffmanCode) {
if(!root) {
return;
}
if(root->data != '$') {
huffmanCode[root->data] = str;
}
generateHuffmanCode(root->left, str + "0", huffmanCode);
generateHuffmanCode(root->right, str + "1", huffmanCode);
}
```
4.将哈夫曼编码写入文件。
```c
fp = fopen("compressed_file.bin", "wb");
for(int i=0; i<strlen(original_file); i++) {
fwrite(huffmanCode[original_file[i]].c_str(), sizeof(char), huffmanCode[original_file[i]].size(), fp);
}
fclose(fp);
```
5.解压缩文件。
```c
fp = fopen("compressed_file.bin", "rb");
while((ch = fgetc(fp)) != EOF) {
str += ch;
for(auto i: huffmanCode) {
if(str == i.second) {
decompressed_file += i.first;
str = "";
}
}
}
fclose(fp);
```
6.计算压缩率。
```c
double compressionRatio = (double)compressedFileSize / originalFileSize;
```
7.比较解压文件是否与原文件内容一致。
```c
if(original_file == decompressed_file) {
printf("Decompressed file is same as original file.\n");
} else {
printf("Decompressed file is not same as original file.\n");
}
```
c语言哈夫曼树压缩解压文件
以下是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;
}
```
阅读全文