- 题目
https://pta.patest.cn/pta/test/3512/exam/4/question/77414 - 分析
该题的大意就是给出一组字符和出现的频率,让我们构造它们的哈夫曼编码。
由于哈夫曼编码不唯一,所以编码方式有多种。然后有M个同学给出了他们的编码方式,让我们判断他们的编码是否正确。正确输出Yes,错误输出No
基本这道题可以分成两大部分解决。
- 构造N个字符的哈夫曼编码,计算带权路径长度WPL。
- 判断每个同学的编码方式是否正确。
构造哈夫曼编码可以利用最小堆。
判断编码方式是否正确,首先要判断每个同学的编码的带权路径长度是否等于之前计算出来的WPL,然后再判断是否有 某一个字符的编码是另一个字符的前缀码 的情况。
代码比较复杂,很容易写错。我的代码也有内存泄漏的缺陷,感觉也有一点混乱,是调试了好多次才通过。
- 我的代码
#include<iostream>
#include<cstdlib>
#include<string>
using namespace std;
#define maxn 65
#define minNum -1
char c[maxn];
int f[maxn];
string codes[maxn];
typedef struct TreeNode* Tree;
struct TreeNode{
int weight;
struct TreeNode* left;
struct TreeNode* right;
TreeNode();
};
TreeNode::TreeNode(){
left = NULL;
right = NULL;
}
typedef struct minHeap* ptrHeap;
struct minHeap{
struct TreeNode data[maxn];
int size;
};
void percDown(int index,int n);
void buildHeap(int n,ptrHeap H);
Tree deleteMin(ptrHeap H);
void insetHeap(Tree T,ptrHeap H);
Tree Huffman(int n,ptrHeap H);
int WPL(Tree T,int depth);
bool checkPrefix(int n);
int main()
{
int N;
ptrHeap H = new(minHeap);
cin>>N;
for(int i=1; i<=N; i++)
{
cin>>c[i]>>f[i];
}
buildHeap(N,H);
Tree T = Huffman(N,H);
int wpl = WPL(T,0);
char ch;
int M,sum;
bool flag;
cin>>M;
for(int j=1; j<=M; j++)
{
sum = 0;
flag = true;
for(int i=1; i<=N; i++)
{
cin>>ch>>codes[i];
sum += codes[i].length()*f[i];
}
if(sum != wpl){
flag = false;
}
if(flag) flag = checkPrefix(N);
if(flag){
cout<<"Yes"<<endl;
}else{
cout<<"No"<<endl;
}
}
return 0;
}
void percDown(int index,ptrHeap H)
{
int parent,child;
TreeNode tmp = H->data[index];
for(parent=index; parent*2<=H->size; parent=child)
{
child = parent*2;
if(child+1<=H->size && H->data[child+1].weight< H->data[child].weight)
{
child++;
}
if(H->data[child].weight < tmp.weight )
{
H->data[parent] = H->data[child];
}else{
break;
}
}
H->data[parent] = tmp;
}
void buildHeap(int n,ptrHeap H)
{
H->size = n;
H->data[0].weight = minNum;
for(int i=1; i<=n; i++) H->data[i].weight = f[i];
for(int i=H->size/2; i>=1; i--) percDown(i,H);
}
Tree deleteMin(ptrHeap H)
{
Tree ans = new TreeNode;
(*ans) = H->data[1];
H->data[1] = H->data[H->size];
H->size--;
percDown(1,H);
return ans;
}
void insetHeap(Tree T,ptrHeap H)
{
int index = ++H->size;
while(T->weight < H->data[index/2].weight)
{
H->data[index] = H->data[index/2];
index /= 2;
}
H->data[index] = *T;
}
Tree Huffman(int n,ptrHeap H)
{
Tree T;
for(int i=1; i<n; i++)
{
T = (Tree)malloc(sizeof(struct TreeNode));
T->left = deleteMin(H);
T->right = deleteMin(H);
T->weight = T->left->weight + T->right->weight;
insetHeap(T,H);
}
T = deleteMin(H);
return T;
}
int WPL(Tree T,int depth)
{
if(T->left==NULL && T->right==NULL){
return (T->weight)*depth;
}else{
return WPL(T->left,depth+1)+WPL(T->right,depth+1);
}
}
bool checkPrefix(int n)
{
bool ans = true;
int len1,len2;
for(int i=1; i<n; i++)
{
len1 = codes[i].length();
for(int j=i+1; j<=n; j++)
{
len2 = codes[j].length();
if(len1 >= len2){
string tmp = codes[i].substr(0,len2);
if(tmp.compare(codes[j]) == 0){
ans = false;
break;
}
}else{
string tmp = codes[j].substr(0,len1);
if(tmp.compare(codes[i]) == 0){
ans = false;
break;
}
}
}
if(ans == false) break;
}
return ans;
}