05-树9 Huffman Codes

05-树9 Huffman Codes   (30分)

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 NN (2\le N\le 632N63), then followed by a line that contains all the NNdistinct 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', '_'}, andf[i] is the frequency of c[i] and is an integer no more than 1000. The next line gives a positive integer MM (\le 10001000), then followed by MMstudent submissions. Each student submission consists of NN 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

题目思路:

就是何老师讲的霍夫曼树,关键是前缀码的判断,这点参考了inaho的思路

#include<stdio.h>
#include <stdlib.h>

#define MinData 0

typedef struct TreeNode *HuffmanTree;
struct TreeNode{
	int weight;
	HuffmanTree left;
	HuffmanTree right;
};
//霍夫曼树

typedef struct HeapStruct *MinHeap; 
struct HeapStruct{
	HuffmanTree elements;
	int size;
	int capacity;
}; 
//最小堆

MinHeap BuildMinHeap(int Maxsize,int weight[]);
MinHeap CreateMinHeap (int Maxsize);
void Insert(MinHeap H,HuffmanTree HT); 
HuffmanTree DeleteMin(MinHeap H);
HuffmanTree Huffman(MinHeap H); 
void GetWpl(HuffmanTree HT,int layer,int *wpl);

int code_length(char *a);  
int compare(char *c1, char *c2); 

int main(int argc, char const *argv[])
{
	//freopen("test.txt","r",stdin); 
	
	int N;
	scanf("%d\n",&N);//一共几个编码 
	
	char c[N];//记录字符 
	int f[N];//记录字符对应权重 
	
	for(int i = 0; i < N; i++)
	{
		if(i == N - 1)
		{
			scanf("%c %d", &c[i], &f[i]); 
		}
		else{
			scanf("%c %d ", &c[i], &f[i]);  
		}
		
	}
	
	MinHeap MH = BuildMinHeap(N,f);
	HuffmanTree HT = Huffman(MH);
	
	int minwpl = 0;
	GetWpl(HT,0,&minwpl);
	
	//读入有多少个编码组合
	int M;
	scanf("%d\n",&M);
	char ch[N],code[N][64]; 

	
	for(int j = 0; j < M; j++)//一共M组 
	{
		for(int i = 0; i < N; i++)///每组N个数 
		{
			scanf("%c %s\n",&ch[i],&code[i]);
		} 
		
	    int flag = 1;//1表示是前缀码//前缀码判断
	
		for (int i = 0; i < N; i++)
		{  
            for (int k = i+1; k < N; ++k)
			{			  
                if(compare(code[i], code[k]))
				{  
                    if(flag)  
                        printf("No\n");  
                    flag = 0;  
                }  
            } 	
		}
	 
	
		int stu_wpl = 0;  //比较wpl 
	    if( flag )
		{  
	        for (int i = 0; i < N; ++i)  
	            stu_wpl += f[i]*code_length(code[i]);  
	        if(minwpl == stu_wpl)  
	            printf("Yes\n");  
	        else  
	            printf("No\n");  
	    } 
	
	
	}
	return 0;  


} 

int code_length(char *a)  
{  
    int len = 0;  
    char *p = a;  
    while(*p != '\0'){  
        p++;  
        len++;  
    }  
    return len;  
}  
  
int compare(char *c1, char *c2)  
{  
    char *a = c1, *b = c2;  
    while(*a!='\0' && *b!='\0'){  
        if(*a != *b)  
            return 0;  
        a++;  
        b++;  
    }  
    return 1;  
}  

MinHeap BuildMinHeap(int Maxsize,int weight[])
{
	int i;
	MinHeap H = CreateMinHeap(Maxsize);
	HuffmanTree temp = (HuffmanTree)malloc(sizeof(struct TreeNode));
	for(int i = 0; i < Maxsize; i++)
	{
		temp->weight = weight[i];
		temp->left = temp->right = NULL;
		Insert(H,temp);
	}
	free(temp);
	return H;
}


MinHeap CreateMinHeap (int Maxsize)
{
	MinHeap H = (MinHeap)malloc(sizeof(struct HeapStruct));
	H->elements = (HuffmanTree)malloc(sizeof(struct TreeNode)*(Maxsize+1));
	//因为Elemens[0]作为哨兵,从[1]开始存放,所以分配MaxSize+1空间  
	H->size = 0;
	H->capacity = Maxsize;
	H->elements[0].weight= MinData;//哨兵 
	return H;
} 

void Insert(MinHeap H,HuffmanTree HT)
{
	int i;
	//将X插入H
	if(H->size == H->capacity){
		printf("最大堆已满!");
		return; 
	} 
	i = ++(H->size); //i指向插入后堆中的最后一个元素的位置(该结点此时为空结点)
	for( ; H->elements[i/2].weight > HT->weight ; i/=2)
	//堆从1开始 
	//不断和父节点比较,父节点大,就往下走 
	{
		H->elements[i].weight = H->elements[i/2].weight;
	} 
	H->elements[i] = *HT;//将X插入;
}

HuffmanTree DeleteMin(MinHeap H)
{
	//从最小堆H中取出键值为最小的元素,并删除一个结点
	int parent, child;
	HuffmanTree MinItem, temp;
	
	MinItem = (HuffmanTree)malloc(sizeof(struct TreeNode));  
    temp = (HuffmanTree)malloc(sizeof(struct TreeNode)); 
	 
	if ( H->size == 0)
	{
		printf("最小堆已为空");
		return NULL; 
	}
	
	*MinItem = H->elements[1];//保存最小的元素 
	*temp = H->elements[H->size--];//从最后一个元素插到顶点来比较 
	
	for(parent=1;parent*2 <= H->size; parent = child)//有没有左儿子 
	{
		child = parent * 2;//有的话比较左儿子 
		if ((child != H->size)&&
		(H->elements[child].weight > H->elements[child+1].weight))
		//比较左右儿子哪个小 
		{
			child ++;
		} 
		if(temp->weight <= H->elements[child].weight)
		{
			break;
		}
		else
		{
			H->elements[parent] = H->elements[child];
		}
	}
	H->elements[parent] = *temp;
	free(temp); 
	return MinItem; 
} 


HuffmanTree Huffman(MinHeap H)
{
	int i; HuffmanTree HT;
	int times = H->size;//H->size的值会发生变化,所以要用另一个变量来存储 
	for( i = 1; i < times ; i++)
	{
		HT = (HuffmanTree)malloc(sizeof(struct TreeNode));
		HT->left = DeleteMin(H);
		HT->right = DeleteMin(H);
		HT->weight = HT->left->weight + HT->right->weight;
		Insert(H,HT);
	}
	HT = DeleteMin(H);
	return 	HT;
}

void GetWpl(HuffmanTree HT,int layer,int *wpl)
{
	if(HT->left== NULL && HT->right == NULL)
	{
		(*wpl) = (*wpl)  + layer * HT->weight;
	}
	else//不是叶节点 
	{
		GetWpl(HT->left,layer+1,wpl);
		GetWpl(HT->right,layer+1,wpl);		 
	}
}































  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值