05-树9 Huffman Codes(C)

日常,这一次,耗费我三天,其实第二天时便已经将 对整个框架有清晰的了解了,(看了解析了),但是一步步排除,确实让我学到了很多。

In 1953, David A. Huffman published his paper "A Method for the Construction of Minimum-Redundancy Codes", and hence printed his name in the history of computer science. As a professor who gives the final exam problem on Huffman codes, I am encountering a big problem: the Huffman codes are NOT unique. For example, given a string "aaaxuaxz", we can observe that the frequencies of the characters 'a', 'x', 'u' and 'z' are 4, 2, 1 and 1, respectively. We may either encode the symbols as {'a'=0, 'x'=10, 'u'=110, 'z'=111}, or in another way as {'a'=1, 'x'=01, 'u'=001, 'z'=000}, both compress the string into 14 bits. Another set of code can be given as {'a'=0, 'x'=11, 'u'=100, 'z'=101}, but {'a'=0, 'x'=01, 'u'=011, 'z'=001} is NOT correct since "aaaxuaxz" and "aazuaxax" can both be decoded from the code 00001011001001. The students are submitting all kinds of codes, and I need a computer program to help me determine which ones are correct and which ones are not.

Input Specification:

Each input file contains one test case. For each case, the first line gives an integer N (2≤N≤63), then followed by a line that contains all the N distinct characters and their frequencies in the following format:

c[1] f[1] c[2] f[2] ... c[N] f[N]

where c[i] is a character chosen from {'0' - '9', 'a' - 'z', 'A' - 'Z', '_'}, and f[i] is the frequency of c[i] and is an integer no more than 1000. The next line gives a positive integer M (≤1000), then followed by M student submissions. Each student submission consists of N lines, each in the format:

c[i] code[i]

where c[i] is the i-th character and code[i] is an non-empty string of no more than 63 '0's and '1's.

Output Specification:

For each test case, print in each line either "Yes" if the student's submission is correct, or "No" if not.

Note: The optimal solution is not necessarily generated by Huffman algorithm. Any prefix code with code length being optimal is considered correct.

Sample Input:

7
A 1 B 1 C 1 D 3 E 3 F 6 G 6
4
A 00000
B 00001
C 0001
D 001
E 01
F 10
G 11
A 01010
B 01011
C 0100
D 011
E 10
F 11
G 00
A 000
B 001
C 010
D 011
E 100
F 101
G 110
A 00000
B 00001
C 0001
D 001
E 00
F 10
G 11

Sample Output:

Yes
Yes
No
No

 面对这样的代码, 务必清晰

typedef struct TNode *HF;
typedef struct Heap *MinHeap;
struct TNode{
	int weight;
	HF Left;
	HF Right;
};
struct Heap{
	HF *data;
	int size;	
	int capacity;
};
MinHeap Init_Heap(int num)
{
	MinHeap H;
	H = (MinHeap)malloc(sizeof(struct Heap));
	H ->data = (HF*)malloc(sizeof(struct TNode) * (num + 1));
	H->data[0] = (HF)malloc(sizeof(struct TNode));
	H ->data[0] ->weight = -1;
	H ->data[0] ->Left = NULL;
	H ->data[0] ->Right = NULL;
	H ->size = 0;
	return H;
}

我,最开始对

H->data[0]=(Huffman)malloc(sizeof(struct TreeNode));

也不解,甚至写出了,

void attach(HF H, HF T)
{
	HF ->weight = T ->weight;
	HF ->Left = T ->Left;
	HF ->Right = T ->Right;
	free(T);
}
//这样的代码

后来明白了HF *data,可以视为 struct TNode **data;

H-> data 指分配了(num+1)大小的指针数组,

H ->data[0]指分配一个struct TNode空间,理解 struct TNode *data[0];(这里data[0])

哈哈,C语言就是这样,指针我也只是粗略的了解,加油

 我的AC代码:

#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<stdbool.h>
#include<string.h>

typedef struct TNode *HF;
typedef struct Heap *MinHeap;
struct TNode{
	int weight;
	HF Left;
	HF Right;
};
struct Heap{
	HF *data;
	int size;	
	int capacity;
};

MinHeap Init_Heap(int num);
HF Init_Huffman();
void Insert_Heap(MinHeap H, HF T);
HF Pop_Node(MinHeap H);
HF Build_Huffman();
HF Build_Huffman(int num, int *code, char *ch);
int WPL(HF T, int depth);
bool Judge_Huffman(int num, int wpl, int *code, char *ch);

int main()
{
	int num;
	HF T;
	MinHeap H;
	char *ch;
	int *code, wpl;
	int test;
	scanf("%d", &num);
	ch = (char*)malloc(sizeof(char) * (num + 1));
	code = (int*)malloc(sizeof(int) * (num + 1));
	T = Build_Huffman(num, code, ch);
	wpl = WPL(T, 0);
	scanf("%d", &test);
	while(test--){
		if(Judge_Huffman(num, wpl, code, ch)){
			printf("Yes\n");
		}else{
			printf("No\n");
		}
	}
	return 0;
}
HF Build_Huffman(int num, int *code, char *ch)
{
	MinHeap H;
	HF T;
	int i, n;
	H = Init_Heap(num);
	for(i = 1; i <= num; i++){
		scanf(" %c %d", &ch[i], &code[i]);
		if(isalpha(ch[i]) && isupper(ch[i]) && code[i] > 0);
		else{
			printf("错误!请检查输入字符。\n");
		}
		T = Init_Huffman();
		T ->weight = code[i];
		Insert_Heap(H, T);
	}
	n = H->size;
	for(int i=1; i < n; i++)
	{
		T= Init_Huffman();
		T->Left = Pop_Node(H);
		T->Right = Pop_Node(H);
		T->weight = T->Left->weight+T->Right->weight;
		Insert_Heap(H,T);
	}
	T = Pop_Node(H);
	return T;
}
int WPL(HF T, int depth)
{
	if(!(T ->Left) && !(T ->Right)){
		return (T ->weight * depth);
	}else{
		return WPL(T ->Left, depth + 1) + WPL(T ->Right, depth + 1);
	}
}
MinHeap Init_Heap(int num)
{
	MinHeap H;
	H = (MinHeap)malloc(sizeof(struct Heap));
	H ->data = (HF*)malloc(sizeof(struct TNode) * (num + 1));
	H->data[0] = (HF)malloc(sizeof(struct TNode));
	H ->data[0] ->weight = -1;
	H ->data[0] ->Left = NULL;
	H ->data[0] ->Right = NULL;
	H ->size = 0;
	return H;
}
HF Init_Huffman()
{
	HF T;
	T = (HF)malloc(sizeof(struct TNode));
	T ->weight = 0;
	T ->Left = NULL;
	T ->Right = NULL;
	return T;
}
void Insert_Heap(MinHeap H, HF T)
{
	int i;
	i = ++(H->size);
	for(; T ->weight < H ->data[i/2]->weight; i /=2){
		H ->data[i] = H ->data[i/2];
	}
	H ->data[i] = T;
}
HF Pop_Node(MinHeap H)
{
	HF Temp, Min;
	int Child, Parent;
	Min = H ->data[1];
	Temp = H ->data[(H ->size)--];
	for(Parent = 1; Parent * 2 <= H ->size; Parent = Child){
		Child = Parent * 2;
		if((Child != H ->size) && (H->data[Child]->weight > H->data[Child+1]->weight)){
			Child++;
		}
		if(Temp ->weight <= H ->data[Child] ->weight) break;
		else{
			H ->data[Parent] = H ->data[Child];
		}
	}
	H ->data[Parent] = Temp;
	return Min;
}
bool Judge_Huffman(int num, int wpl, int *code, char *ch)
{
	HF T, Temp;
	char c, *codes;
	int j, wgh;
	int length = 0;
	bool flag = true;
	T = Init_Huffman();
	codes = (char*)malloc(sizeof(char) * (num - 1));
	if(!codes) printf("没有分配成功\n");
	while(num --){
		scanf(" %c %s", &c, codes);
		for(j = 1; c != ch[j]; j++);
		wgh = code[j];
		Temp = T;
		for( j = 0; j < strlen(codes); j++){
			if(codes[j]=='0'){
				if(!Temp->Left)
					Temp->Left = Init_Huffman();
				Temp = Temp->Left;	
			}else if(codes[j] == '1'){
				if(!Temp->Right)
					Temp->Right = Init_Huffman();
				Temp = Temp->Right;
			}if(Temp->weight){
				flag = false;	
			}
		}
		if(Temp->Left || Temp->Right)
			flag = false;
		else{
			Temp->weight = wgh;
		}
		length += strlen(codes) * Temp->weight;
	}
	free(codes);
	if(length != wpl)
		flag = false;
	return flag;
}
  • 44
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个非常有趣的问题。实现一个基于HuffmanHuffman编码的无损数据压缩程序,可以分为以下几个步骤: 1. 统计每个字符出现的频率,构建Huffman 首先,需要对待压缩的数据进行遍历,统计每个字符出现的频率。然后,使用这些频率构建Huffman。这个过程可以使用堆来实现,具体实现可以参考哈夫曼编码的构造算法。 2. 生成Huffman编码表 构建好Huffman之后,可以根据Huffman的特性,生成每个字符对应的Huffman编码。具体实现可以使用递归的方式,在遍历Huffman的过程中生成Huffman编码表。 3. 将数据进行压缩 有了Huffman编码表之后,就可以对待压缩的数据进行压缩了。具体实现可以将数据中的每个字符替换成对应的Huffman编码,然后将所有的编码拼接在一起,形成一个二进制字符串。 4. 将压缩后的数据写入文件 最后,将压缩后的二进制字符串写入文件中即可。 这里提供一份参考代码,仅供参考: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_CHAR_NUM 256 #define MAX_BIT_NUM 1000000 typedef struct TreeNode { unsigned char data; // 存储字符 int freq; // 存储字符出现的频率 struct TreeNode *left; struct TreeNode *right; } TreeNode; typedef struct Heap { int size; TreeNode *data[MAX_CHAR_NUM*2]; } Heap; typedef struct HuffmanCode { unsigned char data; char code[MAX_BIT_NUM]; } HuffmanCode; void swap(TreeNode **a, TreeNode **b) { TreeNode *temp = *a; *a = *b; *b = temp; } void minHeapify(Heap *heap, int index) { int left = index * 2, right = index * 2 + 1, smallest = index; if (left <= heap->size && heap->data[left]->freq < heap->data[smallest]->freq) smallest = left; if (right <= heap->size && heap->data[right]->freq < heap->data[smallest]->freq) smallest = right; if (smallest != index) { swap(&heap->data[index], &heap->data[smallest]); minHeapify(heap, smallest); } } void buildMinHeap(Heap *heap) { int i; for (i = heap->size / 2; i >= 1; i--) minHeapify(heap, i); } TreeNode *createTreeNode(unsigned char data, int freq) { TreeNode *newNode = (TreeNode*) malloc(sizeof(TreeNode)); newNode->data = data; newNode->freq = freq; newNode->left = NULL; newNode->right = NULL; return newNode; } Heap *createHeap() { Heap *newHeap = (Heap*) malloc(sizeof(Heap)); newHeap->size = 0; return newHeap; } void insertHeap(Heap *heap, TreeNode *node) { heap->size++; heap->data[heap->size] = node; int i = heap->size; while (i > 1 && heap->data[i]->freq < heap->data[i/2]->freq) { swap(&heap->data[i], &heap->data[i/2]); i = i / 2; } } TreeNode *deleteMin(Heap *heap) { TreeNode *minNode = heap->data[1]; heap->data[1] = heap->data[heap->size]; heap->size--; minHeapify(heap, 1); return minNode; } TreeNode *buildHuffmanTree(int freq[]) { int i; Heap *heap = createHeap(); for (i = 0; i < MAX_CHAR_NUM; i++) if (freq[i] > 0) insertHeap(heap, createTreeNode(i, freq[i])); buildMinHeap(heap); while (heap->size > 1) { TreeNode *left = deleteMin(heap); TreeNode *right = deleteMin(heap); TreeNode *parent = createTreeNode('$', left->freq + right->freq); parent->left = left; parent->right = right; insertHeap(heap, parent); } return deleteMin(heap); } void generateHuffmanCode(TreeNode *root, char code[], int depth, HuffmanCode huffmanCodes[]) { if (root->left == NULL && root->right == NULL) { huffmanCodes[root->data].data = root->data; strcpy(huffmanCodes[root->data].code, code); return; } code[depth] = '0'; generateHuffmanCode(root->left, code, depth+1, huffmanCodes); code[depth] = '1'; generateHuffmanCode(root->right, code, depth+1, huffmanCodes); } void compressFile(char *inputFile, char *outputFile, HuffmanCode huffmanCodes[]) { FILE *fin = fopen(inputFile, "rb"); FILE *fout = fopen(outputFile, "wb"); int freq[MAX_CHAR_NUM], i; memset(freq, 0, sizeof(freq)); unsigned char c; while (fread(&c, 1, 1, fin) > 0) freq[c]++; fseek(fin, 0, SEEK_SET); TreeNode *root = buildHuffmanTree(freq); char code[MAX_BIT_NUM]; generateHuffmanCode(root, code, 0, huffmanCodes); int bitCount = 0; char buffer = 0; while (fread(&c, 1, 1, fin) > 0) { for (i = 0; i < strlen(huffmanCodes[c].code); i++) { buffer = buffer << 1; if (huffmanCodes[c].code[i] == '1') buffer |= 1; bitCount++; if (bitCount == 8) { fwrite(&buffer, 1, 1, fout); bitCount = 0; buffer = 0; } } } if (bitCount > 0) { buffer = buffer << (8 - bitCount); fwrite(&buffer, 1, 1, fout); } fclose(fin); fclose(fout); } void decompressFile(char *inputFile, char *outputFile, TreeNode *root) { FILE *fin = fopen(inputFile, "rb"); FILE *fout = fopen(outputFile, "wb"); unsigned char c; TreeNode *p = root; while (fread(&c, 1, 1, fin) > 0) { int i; for (i = 7; i >= 0; i--) { if ((c & (1 << i)) == 0) p = p->left; else p = p->right; if (p->left == NULL && p->right == NULL) { fwrite(&p->data, 1, 1, fout); p = root; } } } fclose(fin); fclose(fout); } int main() { char inputFile[] = "input.txt"; char compressedFile[] = "compressed.bin"; char decompressedFile[] = "decompressed.txt"; HuffmanCode huffmanCodes[MAX_CHAR_NUM]; memset(huffmanCodes, 0, sizeof(huffmanCodes)); compressFile(inputFile, compressedFile, huffmanCodes); TreeNode *root = buildHuffmanTree(NULL); decompressFile(compressedFile, decompressedFile, root); return 0; } ``` 这份代码使用了堆来构建Huffman,使用了递归的方式来生成Huffman编码表,并且实现了对文件进行压缩和解压缩的功能。需要注意的是,对于一个字符集大小为N的情况,Huffman的构建时间复杂度为O(NlogN),压缩和解压缩的时间复杂度也为O(NlogN)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值