您的位置:首页 > 其它

PTA_2019春_059_ Huffman Codes

2019-05-16 23:11 134 查看

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:

 

[code]c[1] f[1] c[2] f[2] ... c
 f

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:

[code]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:

[code]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:

[code]Yes
Yes
No
No
[code]/* Huffman Codes*/
/*思路:将输入的每个字符建树,若每个数为叶节点(叶节点可使其不出现二义性),且满足最短编码,为正确编码
最短编码可由哈夫曼树获得
不需要判断为叶节点,直接判断一个字母是否是另一个字母的前缀来避免二义性*/
/*总感觉树不应该用链式来建,后序操作太过麻烦(遍历,从下往上,找值等等操作),考虑一下用结构体数组来*/
/*5/16/19: 判断是否为前缀码时没有考虑两个码一样*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct data* Data;
struct data {
char a;
int num;
};
typedef struct studentdata* Sdata;  /*学生输入数据结构*/
struct studentdata {
char a;
char array[70];

};
typedef struct HFnode* HFtree;
struct HFnode {   /*哈夫曼树定义*/
int weight;  /*权值*/
char data;
HFtree left;
HFtree right;
HFtree parent;  /*方便回溯*/
};
typedef struct Hnode* Heap;/*堆的定义*/
struct Hnode {
HFtree* data;
int size;
int capacity;
};
typedef struct Snode* Stack; /*堆栈*/
struct Snode {
HFtree* data;
int top;
int maxsize;
};

void insert(Heap H, HFtree tree);   /*最小堆插入*/
HFtree deletemin(Heap H);  /*堆删除*/
void traversal(HFtree T);  /*测试用的遍历*/
Stack creatstack(int maxsize);  /*创建栈*/
void push(Stack S, HFtree T); /*进栈*/
HFtree pop(Stack S);  /*出栈*/
int isempty(Stack S); /*是否为空*/
HFtree find(HFtree T, char a);  /*在哈弗树中找节点*/
int WPL(HFtree T, Data array, int N); /*计算wpl*/
void isture(int wpl, int N, Data indata); /*判断是否符合题意*/
int ispre(int N, Sdata sdata);  /*判断是否为前缀编码*/
int max(int a, int b);  /*获得两者较大值*/

int main() {
int N;/*节点个数*/
char laji;/*消除\n 和空格*/
scanf("%d", &N);
Data indata = (Data)malloc(N * sizeof(struct data));
for (int i = 0; i < N; i++) {
scanf("%c", &laji);
scanf("%c", &indata[i].a);
scanf("%d", &indata[i].num);
}

/*创建最小堆,并将输入的数据存在最小堆中,留着建树用*/
Heap minheap = (Heap)malloc(sizeof(struct Hnode));
minheap->data = (HFtree*)malloc((N + 1) * sizeof(HFtree));    /*下面几行给我往死了里理解,想想自己为什么一开始是错的*/
for (int i = 0; i < N + 1; i++) {
minheap->data[i] = (HFtree)malloc(sizeof(struct HFnode));
}

minheap->size = 0;
minheap->capacity = N;
minheap->data[0]->weight = -2;
minheap->data[0]->left = minheap->data[0]->right = minheap->data[0]->parent = NULL;

for (int i = 0; i < N; i++) {
HFtree hftree = (HFtree)malloc(sizeof(struct HFnode));
hftree->data = indata[i].a;
hftree->weight = indata[i].num;
hftree->left = hftree->right = hftree->parent = NULL;
insert(minheap, hftree);
}/*最小堆建成*/

/*建树*/
HFtree T;
for (int i = 1; i < N; i++) {
T = (HFtree)malloc(sizeof(struct HFnode));
T->parent = NULL;
T->left = deletemin(minheap);
T->left->parent = T;
T->right = deletemin(minheap);
T->right->parent = T;
T->weight = T->left->weight + T->right->weight;
insert(minheap, T);
}
T = deletemin(minheap);/*堆中最后一个元素即树的根节点*/
//traversal(T);

/*获得最小编码数*/
/*测试find函数*/
int wpl;       /*最小编码数*/
wpl = WPL(T, indata, N);
/*测试*/
//	printf("wpl is %d\n", wpl);
/*处理学生的输入数据*/
int L;/*学生个数*/
scanf("%d", &L);
scanf("%c", &laji);
for (int j = 0; j < L; j++) {
isture(wpl, N, indata);
}
return 0;
}
void insert(Heap H, HFtree tree) {
int i;
H->size++;
i = H->size; /*i指向将要插入的位置*/
for (; H->data[i / 2]->weight > tree->weight; i /= 2) {
H->data[i] = H->data[i / 2];
}
H->data[i] = tree;

}
HFtree deletemin(Heap H) {
int parent, child;
HFtree min, x;
min = H->data[1];/*先取出最小值*/
/*下面重新调整*/
x = H->data[H->size];
H->size--;
for (parent = 1; parent * 2 <= H->size; parent = child) {
child = 2 * parent;
if ((child != H->size) && (H->data[child]->weight > H->data[child + 1]->weight)) {
child++;
}
if (x->weight <= H->data[child]->weight) break;
else {
H->data[parent] = H->data[child];
}
}
H->data[parent] = x;
return min;
}
void traversal(HFtree T) {
if (T) {
traversal(T->left);
traversal(T->right);
if (!T->left && !T->right) {

printf("%c\n", T->data);
}
}
}
Stack creatstack(int maxsize) {
Stack S = (Stack)malloc(sizeof(struct Snode));
S->data = (HFtree*)malloc(maxsize * (sizeof(HFtree)));  /*此处同上面那个重要的错误*/
S->maxsize = maxsize;
S->top = -1;
return S;
}
void push(Stack S, HFtree T) {
S->data[++(S->top)] = T;
}
HFtree pop(Stack S) {
return(S->data[(S->top)--]);
}
int isempty(Stack S) {
return(S->top == -1);
}
HFtree find(HFtree T, char a) {
HFtree tree;
Stack S = creatstack(500);
tree = T;
while (tree || isempty(S) != 1) {
while (tree) {
push(S, tree);
tree = tree->left;
}
tree = pop(S);
if (!tree->left && !tree->right) {
if (tree->data == a) return tree;
}
tree=tree->right;
}
}
int WPL(HFtree T, Data array, int N) {
int cnt = 0;
int weight;
HFtree tree;
for (int i = 0; i < N; i++) {
int k = 0;  /*路径长度*/
tree = find(T, array[i].a);
weight = tree->weight;
while (1) {
if (tree == T) break;
tree = tree->parent;
k++;
}
cnt = cnt + k * weight;
}
return cnt;
}
void isture(int wpl, int N, Data indata) {
int student_wpl = 0;
char laji;
Sdata sdata = (Sdata)malloc(N * sizeof(struct studentdata));
for (int i = 0; i < N; i++) {
scanf("%c", &sdata[i].a);
scanf("%c", &laji);
gets(sdata[i].array);
}
/*测试,sdata数组没有问题*/
for (int i = 0; i < N; i++) {
student_wpl = student_wpl + indata[i].num * strlen(sdata[i].array);/*默认两数组的元素对应*/
}
if (wpl == student_wpl) {
if (ispre(N, sdata))  printf("Yes\n");
else printf("No\n");
}
else printf("No\n");

}
int ispre(int N, Sdata sdata) {/*两个字符串一个一个进行对比,当不同时,若此时其中一个字符串已经结束,那么不符合前缀*/
for (int i = 0; i < N-1; i++) {
for (int j = i + 1; j < N; j++) {
for (int k = 0;k<70; k++) {
if (sdata[i].array[k] != sdata[j].array[k]) {      /*当两个字符串比较到不相等时,判断此时是否有字符串遍历结束,若有结束则不为前缀*/
if (strlen(sdata[i].array) == k || strlen(sdata[j].array) == k) {
return 0;
}
break;
}
if(k==68)  return 0;     /*两个编码一样*/
}
}
}
return 1;
}
int max(int a, int b) {
if (a > b)  return a;
else return b;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: