Huffman文件解码

【问题描述】

给定一组字符的Huffman编码表(从标准输入读取),以及一个用该编码表进行编码的Huffman编码文件(存在当前目录下的in.txt中),编写程序实现对Huffman编码文件的解码,并按照后序遍历序列输出解码过程中Huffman树(规定树中左分支表示0,右分支表示1)中各结点的访问次数。

例如给定的一组字符的Huffman编码表为:

6
1:111
2:0
+:110
*:1010
=:1011
8:100

第一行的6表示要对6个不同的字符进行编码,后面每行中冒号(:)左边的字符为待编码的字符,右边为其Huffman编码,冒号两边无空格。对于该编码表,对应的Huffman树(树中左分支表示0,右分支表示1)应为:

 

假如给定的Huffman编码文件in.txt中的内容(由0和1字符组成的序列)为:

111011001010011001011111100

则遍历上述Huffman树即可对该文件进行解码,解码后的文件内容为:

12+2*2+2=18

解码过程中,经过Huffman树中各结点的遍边次数见下图中结点中的数字:

 

对该Huffman树中各结点的访问次数按照后序序列输出应为:

4 1 1 1 2 3 2 2 4 7 11

【输入形式】

先从标准输入读入待编码的字符个数(大于等于2,小于等于50),然后分行输入各字符的Huffman编码(先输入字符,再输入其编码,字符和编码中间以一个英文字符冒号:分隔),编码只由0和1组成。

Huffman编码文件为当前目录下的in.txt文本文件,即:其中的0和1都是以单个字符的形式存储,文件末尾有一个回车换行符。

【输出形式】

先将解码后的文件内容输出到标准输出上(独占一行);然后以后序遍历序列输出解码过程中Huffman树中各结点的访问次数,各数据间以一个空格分隔,最后一个数据后也有一个空格。

【样例输入】

6
1:111
2:0
+:110
*:1010
=:1011
8:100

假如in.txt中的内容为:

111011001010011001011111100

【样例输出】

12+2*2+2=18
4 1 1 1 2 3 2 2 4 7 11

【样例说明】

从标准输入读取了6个字符的Huffman编码,因为规定Huffman树中左分支表示0,右分支表示1,所以利用该编码表可构造上述Huffman树(见图1)。遍历该Huffman树对编码文件in.txt的进行解码,即可得到解码后的原文件内容,遍历过程中各树中结点的最终访问次数要按照后序遍历序列输出。

【评分标准】

该题要求根据字符的Huffman编码表对编码文件进行解码

题解:

#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
	char name;
	int time;
	int found;
	Node* LeftChild;
	Node* RightChild;
}Node;
Node* root = (Node*)malloc(sizeof(Node));
void build(char name,char code[]){//根据哈夫曼编码构造哈夫曼树 
	Node* tree = root;
	int i = 0;
	for(i = 0;code[i] == '0' || code[i] == '1';i++){//通过01编码从根开始寻找字符对应结点,0代表左子结点,1代表右子结点 
		if(code[i] == '0'){
			if(tree->LeftChild == NULL){//若找不到此节点则新建节点 
				tree->LeftChild = (Node*)malloc(sizeof(Node));
				tree = tree->LeftChild;
				tree->time = 0;
				tree->found = 0;
				tree->LeftChild = NULL;
				tree->RightChild = NULL;
			}
			else tree = tree ->LeftChild;
		}
		if(code[i] == '1'){
			if(tree->RightChild == NULL){
				tree->RightChild = (Node*)malloc(sizeof(Node));
				tree = tree->RightChild;
				tree->time = 0;
				tree->found = 0;
				tree->LeftChild = NULL;
				tree->RightChild = NULL;
			}
			else tree = tree ->RightChild;
		}
	}
	tree->name = name;
}
Node* find(Node* tree){
	if(tree->LeftChild != NULL && tree->LeftChild->found != 1) find(tree->LeftChild);
	if(tree->RightChild != NULL && tree->RightChild->found != 1) find(tree->RightChild);//后序遍历 
	printf("%d ",tree->time);
	tree->found = 1;
	return tree;
}
int main(){
	int n;
	root->LeftChild = NULL;
	root->RightChild = NULL;
	root->found = 0;
	root->time = 0;
	scanf("%d",&n);
	getchar();
	char name[100];
	char code[100][50];
	for(int i =0;i<n;i++){
		scanf("%c:%s",&name[i],code[i]);
		getchar();
		build(name[i],code[i]);
	}//输入编码表 
	FILE* fp = fopen("in.txt","r+");
	char a[1000];
	int num = 0;
	for(;fscanf(fp,"%c",&a[num]) != EOF;num++);//读入代码 
	Node* tree = root;
	for(int i =0;i<num;i++){//根据读入的0,1编码从根节点开始搜寻,找到叶节点时输出叶节点对应字符 
		if(a[i] =='0'){
			if(tree->LeftChild == NULL){
				printf("%c",tree->name);
				tree->time++;//遍历经过某一节点是,++其被遍历次数 
				tree = root->LeftChild;
				root->time++;
			}
			else {
				tree->time++;
				tree = tree->LeftChild;
			}
		}
		else if(a[i]=='1'){
			if(tree->RightChild == NULL){
				printf("%c",tree->name);
				tree->time++;
				tree = root->RightChild;
				root->time++;
			}
			else {
				tree->time++;
				tree = tree->RightChild;
			}			
		}
	}
	tree->time++;
	printf("%c", tree->name);
	printf("\n");
	for(;find(root)!=root;);//后序遍历 
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Huffman编码是一种无损压缩算法,常用于数据传输和存储中。下面是C语言实现Huffman编码和解码的基本思路: Huffman编码: 1. 统计字符出现频率,构建字符频率表; 2. 将字符频率表中的字符和频率信息构建成一棵Huffman树; 3. 遍历Huffman树,给每个字符生成对应的Huffman编码; 4. 将编码写入文件Huffman解码: 1. 读取压缩文件中的编码信息和字符频率表; 2. 根据字符频率表构建Huffman树; 3. 遍历Huffman树,根据编码信息还原原始字符串。 以下是C语言实现Huffman编码和解码的参考代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_TREE_HT 100 // Huffman树节点结构体 struct MinHeapNode { char data; unsigned freq; struct MinHeapNode *left, *right; }; // Huffman编码表结构体 struct HuffmanCode { char data; char *code; }; // 最小优先队列结构体 struct MinHeap { unsigned size; unsigned capacity; struct MinHeapNode **array; }; // 创建一个新的Huffman树节点 struct MinHeapNode* newNode(char data, unsigned freq) { struct MinHeapNode* node = (struct MinHeapNode*)malloc(sizeof(struct MinHeapNode)); node->left = node->right = NULL; node->data = data; node->freq = freq; return node; } // 创建一个最小优先队列 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); } } // 检查堆大小是否为1 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); } // 判断是否是叶子节点 int isLeaf(struct MinHeapNode* root) { return !(root->left) && !(root->right); } // 创建一个最小优先队列并构建Huffman树 struct MinHeap* createAndBuildMinHeap(char data[], int freq[], int size) { int i; struct MinHeap* minHeap = createMinHeap(size); for (i = 0; i < size; ++i) minHeap->array[i] = newNode(data[i], freq[i]); minHeap->size = size; buildMinHeap(minHeap); return minHeap; } // 构建Huffman树 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); } // 生成Huffman编码 void generateCodes(struct MinHeapNode* root, char *code, int top, struct HuffmanCode *huffmanCode) { if (root->left) { code[top] = '0'; generateCodes(root->left, code, top + 1, huffmanCode); } if (root->right) { code[top] = '1'; generateCodes(root->right, code, top + 1, huffmanCode); } if (isLeaf(root)) { huffmanCode[root->data].data = root->data; huffmanCode[root->data].code = (char*)malloc((top + 1) * sizeof(char)); memcpy(huffmanCode[root->data].code, code, (top + 1) * sizeof(char)); } } // 打印Huffman编码表 void printHuffmanCodes(struct HuffmanCode *huffmanCode, int size) { int i; printf("Huffman编码表:\n"); for (i = 0; i < size; ++i) printf("%c: %s\n", huffmanCode[i].data, huffmanCode[i].code); } // 压缩文件 void compressFile(char *fileName, struct HuffmanCode *huffmanCode, int size) { FILE *fpIn, *fpOut; char ch, *code; int i, j, len; fpIn = fopen(fileName, "r"); if (fpIn == NULL) { printf("打开文件失败!\n"); return; } fpOut = fopen("compressed.dat", "wb"); fwrite(&size, sizeof(int), 1, fpOut); for (i = 0; i < size; ++i) { fwrite(&huffmanCode[i].data, sizeof(char), 1, fpOut); len = strlen(huffmanCode[i].code); fwrite(&len, sizeof(int), 1, fpOut); fwrite(huffmanCode[i].code, sizeof(char), len, fpOut); } code = (char*)malloc(MAX_TREE_HT * sizeof(char)); while ((ch = fgetc(fpIn)) != EOF) { for (i = 0; i < size; ++i) { if (huffmanCode[i].data == ch) { len = strlen(huffmanCode[i].code); for (j = 0; j < len; ++j) code[j] = huffmanCode[i].code[j]; fwrite(code, sizeof(char), len, fpOut); break; } } } fclose(fpIn); fclose(fpOut); printf("压缩成功!\n"); } // 解压文件 void decompressFile(char *fileName) { FILE *fpIn, *fpOut; struct HuffmanCode huffmanCode[256]; char ch, *code; int i, j, len, size; fpIn = fopen(fileName, "rb"); if (fpIn == NULL) { printf("打开文件失败!\n"); return; } fpOut = fopen("decompressed.txt", "w"); fread(&size, sizeof(int), 1, fpIn); for (i = 0; i < size; ++i) { fread(&huffmanCode[i].data, sizeof(char), 1, fpIn); fread(&len, sizeof(int), 1, fpIn); huffmanCode[i].code = (char*)malloc((len + 1) * sizeof(char)); fread(huffmanCode[i].code, sizeof(char), len, fpIn); huffmanCode[i].code[len] = '\0'; } code = (char*)malloc(MAX_TREE_HT * sizeof(char)); struct MinHeapNode *root = buildHuffmanTree(NULL, NULL, 0); struct MinHeapNode *curr = root; while ((ch = fgetc(fpIn)) != EOF) { for (i = 0; i < 8; ++i) { if (ch & (1 << (7 - i))) // ASCII码从高位开始读 curr = curr->right; else curr = curr->left; if (isLeaf(curr)) { fputc(curr->data, fpOut); curr = root; } } } fclose(fpIn); fclose(fpOut); printf("解压成功!\n"); } int main() { char data[] = {'a', 'b', 'c', 'd', 'e', 'f'}; int freq[] = {5, 9, 12, 13, 16, 45}; int size = sizeof(data) / sizeof(data[0]); struct HuffmanCode huffmanCode[256]; struct MinHeapNode* root = buildHuffmanTree(data, freq, size); char code[MAX_TREE_HT]; int top = 0; generateCodes(root, code, top, huffmanCode); printHuffmanCodes(huffmanCode, size); compressFile("input.txt", huffmanCode, size); decompressFile("compressed.dat"); return 0; } ``` 上述代码中,我们使用了最小优先队列来构建Huffman树。在生成Huffman编码时,我们使用了递归的方法遍历树,并记录下每个叶子节点的编码。在压缩文件时,我们将字符的Huffman编码写入输出文件中。在解压文件时,我们读取压缩文件中的编码信息和字符频率表,根据它们构建Huffman树,并根据编码信息还原原始字符串。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值