哈夫曼编码的压缩与解压缩
时间: 2023-10-22 12:25:18 浏览: 137
哈夫曼编码是一种基于字符出现频率的压缩算法,它将出现频率高的字符用短的编码表示,出现频率低的字符用长的编码表示,从而达到压缩文本的目的。压缩时,将原始文本按字符出现频率构建哈夫曼树,并根据哈夫曼树生成每个字符的哈夫曼编码,将编码后的文本存储到文件中。解压时,读取压缩文件中的编码,根据哈夫曼树将编码还原为原始文本。
具体的压缩过程如下:
1. 统计原始文本中每个字符出现的频率。
2. 根据频率构建哈夫曼树,出现频率高的字符离根节点近,出现频率低的字符离根节点远。
3. 从根节点开始,向左走表示“0”,向右走表示“1”,递归遍历哈夫曼树,生成每个字符的哈夫曼编码。
4. 将编码后的文本按位存储到文件中,每8位组成一个字节,存储到二进制文件中。
具体的解压缩过程如下:
1. 读取压缩文件中的编码,按位(bit)读取,遍历哈夫曼树,将编码还原为原始文本。
2. 将还原后的文本存储到文件中。
需要注意的是,压缩时需要将哈夫曼树的结构也存储到文件中,以便解压缩时重建哈夫曼树。此外,由于哈夫曼编码不是固定长度的,因此压缩后的文件大小并不确定,可能会比原始文本大,这是因为压缩文件中还需要存储哈夫曼树的结构和一些额外信息。
相关问题
哈夫曼编码压缩解压缩c语言代码
以下是哈夫曼编码压缩解压缩的C语言代码示例:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_TREE_HT 100
struct MinHeapNode {
char data;
unsigned freq;
struct MinHeapNode *left, *right;
};
struct MinHeap {
unsigned size;
unsigned capacity;
struct MinHeapNode** array;
};
struct MinHeapNode* newNode(char data, unsigned freq) {
struct MinHeapNode* temp = (struct MinHeapNode*)malloc(sizeof(struct MinHeapNode));
temp->left = temp->right = NULL;
temp->data = data;
temp->freq = freq;
return temp;
}
struct MinHeap* createMinHeap(unsigned capacity) {
struct MinHeap* minHeap = (struct MinHeap*)malloc(sizeof(struct MinHeap));
minHeap->size = 0;
minHeap->capacity = capacity;
minHeap->array = (struct MinHeapNode**)malloc(minHeap->capacity * sizeof(struct MinHeapNode*));
return minHeap;
}
void swapMinHeapNode(struct MinHeapNode** a, struct MinHeapNode** b) {
struct MinHeapNode* t = *a;
*a = *b;
*b = t;
}
void minHeapify(struct MinHeap* minHeap, int idx) {
int smallest = idx;
int left = 2 * idx + 1;
int right = 2 * idx + 2;
if (left < minHeap->size && minHeap->array[left]->freq < minHeap->array[smallest]->freq)
smallest = left;
if (right < minHeap->size && minHeap->array[right]->freq < minHeap->array[smallest]->freq)
smallest = right;
if (smallest != idx) {
swapMinHeapNode(&minHeap->array[smallest], &minHeap->array[idx]);
minHeapify(minHeap, smallest);
}
}
int isSizeOne(struct MinHeap* minHeap) {
return (minHeap->size == 1);
}
struct MinHeapNode* extractMin(struct MinHeap* minHeap) {
struct MinHeapNode* temp = minHeap->array[0];
minHeap->array[0] = minHeap->array[minHeap->size - 1];
--minHeap->size;
minHeapify(minHeap, 0);
return temp;
}
void insertMinHeap(struct MinHeap* minHeap, struct MinHeapNode* minHeapNode) {
++minHeap->size;
int i = minHeap->size - 1;
while (i && minHeapNode->freq < minHeap->array[(i - 1) / 2]->freq) {
minHeap->array[i] = minHeap->array[(i - 1) / 2];
i = (i - 1) / 2;
}
minHeap->array[i] = minHeapNode;
}
void buildMinHeap(struct MinHeap* minHeap) {
int n = minHeap->size - 1;
int i;
for (i = (n - 1) / 2; i >= 0; --i)
minHeapify(minHeap, i);
}
void printArr(int arr[], int n) {
int i;
for (i = 0; i < n; ++i)
printf("%d", arr[i]);
printf("\n");
}
int isLeaf(struct MinHeapNode* root) {
return !(root->left) && !(root->right);
}
struct MinHeap* createAndBuildMinHeap(char data[], int freq[], int size) {
struct MinHeap* minHeap = createMinHeap(size);
for (int i = 0; i < size; ++i)
minHeap->array[i] = newNode(data[i], freq[i]);
minHeap->size = size;
buildMinHeap(minHeap);
return minHeap;
}
struct MinHeapNode* buildHuffmanTree(char data[], int freq[], int size) {
struct MinHeapNode *left, *right, *top;
struct MinHeap* minHeap = createAndBuildMinHeap(data, freq, size);
while (!isSizeOne(minHeap)) {
left = extractMin(minHeap);
right = extractMin(minHeap);
top = newNode('$', left->freq + right->freq);
top->left = left;
top->right = right;
insertMinHeap(minHeap, top);
}
return extractMin(minHeap);
}
void printCodes(struct MinHeapNode* root, int arr[], int top) {
if (root->left) {
arr[top] = 0;
printCodes(root->left, arr, top + 1);
}
if (root->right) {
arr[top] = 1;
printCodes(root->right, arr, top + 1);
}
if (isLeaf(root)) {
printf("%c: ", root->data);
printArr(arr, top);
}
}
void HuffmanCodes(char data[], int freq[], int size) {
struct MinHeapNode* root = buildHuffmanTree(data, freq, size);
int arr[MAX_TREE_HT], top = 0;
printCodes(root, arr, top);
}
void compress(char* inputFilePath, char* outputFilePath) {
FILE* inputFile = fopen(inputFilePath, "rb");
if (!inputFile) {
printf("Error: Could not open file %s.\n", inputFilePath);
return;
}
fseek(inputFile, 0, SEEK_END);
unsigned long inputSize = ftell(inputFile);
fseek(inputFile, 0, SEEK_SET);
char* inputData = (char*)malloc(inputSize);
fread(inputData, 1, inputSize, inputFile);
fclose(inputFile);
int freq[256] = { 0 };
for (int i = 0; i < inputSize; ++i)
++freq[inputData[i]];
char data[256];
int size = 0;
for (int i = 0; i < 256; ++i) {
if (freq[i] != 0) {
data[size] = (char)i;
++size;
}
}
HuffmanCodes(data, freq, size);
FILE* outputFile = fopen(outputFilePath, "wb");
if (!outputFile) {
printf("Error: Could not create file %s.\n", outputFilePath);
return;
}
struct MinHeapNode* root = buildHuffmanTree(data, freq, size);
int arr[MAX_TREE_HT], top = 0;
printCodes(root, arr, top);
fwrite(&size, sizeof(size), 1, outputFile);
for (int i = 0; i < size; ++i) {
fwrite(&data[i], sizeof(data[i]), 1, outputFile);
fwrite(&freq[(unsigned char)data[i]], sizeof(freq[(unsigned char)data[i]]), 1, outputFile);
}
int bitIndex = 0;
char byte = 0;
for (int i = 0; i < inputSize; ++i) {
int arrIndex = 0;
struct MinHeapNode* node = root;
while (inputData[i] != node->data) {
if (inputData[i] < node->data)
node = node->left;
else
node = node->right;
arrIndex++;
}
for (int j = 0; j < arrIndex; ++j) {
byte |= ((arr[j] << (bitIndex % 8)) & (1 << (bitIndex % 8)));
++bitIndex;
if (bitIndex % 8 == 0) {
fwrite(&byte, sizeof(byte), 1, outputFile);
byte = 0;
}
}
}
if (bitIndex % 8 != 0)
fwrite(&byte, sizeof(byte), 1, outputFile);
fclose(outputFile);
printf("Compression complete. Original size: %lu bytes. Compressed size: %ld bytes.\n", inputSize, ftell(outputFile));
}
void decompress(char* inputFilePath, char* outputFilePath) {
FILE* inputFile = fopen(inputFilePath, "rb");
if (!inputFile) {
printf("Error: Could not open file %s.\n", inputFilePath);
return;
}
int size;
fread(&size, sizeof(size), 1, inputFile);
char data[256];
int freq[256];
for (int i = 0; i < size; ++i) {
fread(&data[i], sizeof(data[i]), 1, inputFile);
fread(&freq[(unsigned char)data[i]], sizeof(freq[(unsigned char)data[i]]), 1, inputFile);
}
struct MinHeapNode* root = buildHuffmanTree(data, freq, size);
FILE* outputFile = fopen(outputFilePath, "wb");
if (!outputFile) {
printf("Error: Could not create file %s.\n", outputFilePath);
return;
}
unsigned long outputSize = 0;
int bitIndex = 0;
char byte = 0;
struct MinHeapNode* node = root;
while (1) {
int bit = fgetc(inputFile);
if (bit == EOF)
break;
for (int i = 0; i < 8; ++i) {
if (bit & (1 << i))
node = node->right;
else
node = node->left;
if (isLeaf(node)) {
fwrite(&node->data, sizeof(node->data), 1, outputFile);
outputSize += sizeof(node->data);
node = root;
}
}
}
fclose(inputFile);
fclose(outputFile);
printf("Decompression complete. Original size: %d bytes. Decompressed size: %lu bytes.\n", size, outputSize);
}
int main() {
char inputFilePath[] = "input.txt";
char compressedFilePath[] = "compressed.bin";
char decompressedFilePath[] = "decompressed.txt";
compress(inputFilePath, compressedFilePath);
decompress(compressedFilePath, decompressedFilePath);
return 0;
}
```
该示例包括哈夫曼树的构建、编码、压缩和解码、解压缩等功能。其中,compress函数将输入文件进行压缩,并将压缩结果写入到输出文件中;decompress函数将压缩文件进行解压缩,并将解压缩结果写入到输出文件中。
简单哈夫曼编码的压缩与解压缩c++
### 回答1:
简单哈夫曼编码是一种基于字符频率的无损压缩算法。其压缩过程主要包括两个步骤:建立编码表和将原文本按编码表进行编码。解压缩则是对编码后的数据进行解码,还原为原始文本。
在建立编码表的步骤中,首先需要统计原文本中每个字符的频率,并按频率进行排序。然后从频率最低的两个字符开始,不断合并形成新的节点,直到只剩下一个根节点。这个过程类似于二叉树的构建。在合并节点的过程中,会为每个节点分配一个二进制编码,通过向左走表示编码位0,向右走表示编码位1。最终,所有字符的编码位通过遍历树的路径得到,构成了编码表。
在编码过程中,根据编码表将原文本中的每个字符用相应的二进制编码进行替换。由于编码表保证了每个字符的编码都是唯一的且互不重叠,所以通过替换后的编码所得到的二进制数据长度更短,实现了压缩效果。
解压缩过程中,根据编码表将编码后的二进制数据进行解码。从根节点开始,按照解码规则依次向左或向右移动,直到达到叶节点。到达叶节点后,就可以得到对应的字符。重复此过程,直到解码完所有的二进制数据,就能够得到原始文本。
简单哈夫曼编码的压缩与解压缩过程简单高效,可以有效地减小数据的存储空间,同时不会损失任何信息。然而,它的效果受限于原文本中字符频率的分布情况,如果字符频率分布不均匀,有些字符频率很高,有些频率很低,那么简单哈夫曼编码的压缩效果可能不太明显。
### 回答2:
简单哈夫曼编码是一种常见的数据压缩算法,它通过对字符出现频率进行统计,然后将频率较高的字符用较短的二进制码表示,频率较低的字符用较长的二进制码表示,从而实现对数据的压缩。
对于压缩,首先需要进行编码。步骤如下:
1. 统计输入的字符频率。
2. 根据字符频率构建哈夫曼树。此时,每个字符都表示一个叶子节点,其权值为字符的频率。
3. 从根节点遍历哈夫曼树,记录路径,将路径上的0和1分别表示为二进制码的0和1。
4. 将编码后的结果写入到输出文件中。
对于解压缩,首先需要进行解码。步骤如下:
1. 读取压缩文件的内容,构建哈夫曼树。
2. 从根节点开始,按照读取到的0和1,依次从哈夫曼树的左右子节点中选择。直到达到叶子节点,将其对应的字符写入解压文件中。
简单哈夫曼编码虽然简单,但是却有一些限制。例如,它无法处理包含大量重复字符的数据,因为在哈夫曼树中,较高频率的字符对应的编码较短,而重复字符的编码会变得很长,导致整体压缩效果不佳。此外,简单哈夫曼编码不支持随机访问,因为解码时需要按顺序读取压缩文件的内容。
尽管存在一些限制,简单哈夫曼编码仍然是一种常用的数据压缩算法,因为它相对简单,且在某些情况下能够获得很好的压缩效果。通过合理的设计编码策略,能够进一步提升压缩效果。
### 回答3:
哈夫曼编码是一种常用的数据压缩算法,其原理是将出现频率较高的字符用较短的编码表示,而出现频率较低的字符用较长的编码表示,这样可以实现对数据的有效压缩。
简单哈夫曼编码主要分为两个步骤:构建哈夫曼树和生成编码表。
在压缩过程中,首先需要统计待压缩数据中每个字符的频率,然后根据频率构建哈夫曼树。构建哈夫曼树的过程如下:将所有字符和对应的频率作为叶子节点,然后将频率最小的两个叶子节点合并为一个新的节点,其频率为原来两个节点频率之和;重复进行这个过程,直到只剩下一个根节点为止,此时构建完整的哈夫曼树。
生成编码表的过程如下:从根节点开始,遍历哈夫曼树的每个节点,当到达叶子节点时,记录路径上的编码值。
在解压缩过程中,首先读取压缩文件中的哈夫曼编码表和压缩数据,然后根据哈夫曼编码表重构哈夫曼树。接下来按位读取压缩数据,根据哈夫曼树进行解码,直到解码完所有数据,即可得到原始数据。
简单哈夫曼编码的压缩与解压缩过程可以通过C语言实现。在压缩过程中,可以使用优先队列来实现哈夫曼树的构建,并使用动态字符数组来存储编码表。在解压缩过程中,可以使用位操作来读取压缩数据,并根据哈夫曼树逐位解码。具体实现的细节会涉及到数据结构和文件操作等方面的知识。
总的来说,简单哈夫曼编码通过统计字符频率,并构建哈夫曼树生成编码表,实现对数据的压缩和解压缩。在实际应用中,哈夫曼编码可以大大减小数据的存储空间,提高数据传输的效率。
阅读全文