解题思路:
建立哈夫曼树需要利用最小堆
先判断带权路径长度WPL是否正确
判断是否为前缀编码,即所有的字符都出现在叶节点
有几点需要注意的:
1.最小堆的建立,定义哨兵,其weight为-1,从data[1]开始存储
2.最小堆弹出根节点建立哈夫曼树,在构建哈夫曼树的时候,要注意树的规模在改变;最小堆是通过数组来存储的。
3.最小堆弹出节点的时候,先申请一块节点空间用来存储弹出来的根节点;然后将最后一个节点填充,再调整成最小堆。
4.建立哈夫曼树也需要把计算的权值Insert到最小堆。
5.判断是否为前缀编码:每次遍历完一个编码之后,就在最后一个节点立个flag;这样再有编码经过该节点,就会返回错误;如果编码没有经过上面的叶子节点,则需要通过判断是否为叶子节点来判断。哈夫曼树的所有编码节点都是叶子节点。
代码如下,此为历经5-6小时的结果:
#include <iostream>
#include <string>
using namespace std;
const int maxn = 64; //每个哈夫曼编码不超过63位
typedef struct TreeNode* HuffmanTree;
struct TreeNode { //定义树的结点 -- 哈夫曼树的节点
int weight = 0;
HuffmanTree left = NULL;
HuffmanTree right = NULL;
};
typedef struct HeapNode* MinHeap;//对权值建立最小堆
struct HeapNode {
TreeNode data[maxn];
int size = 0;
};
typedef struct JNode* Newtree;//对权值建立最小堆
struct JNode {
int Flag = 0;
Newtree left = NULL;
Newtree right = NULL;
};
MinHeap createHeap() {
MinHeap H = new(HeapNode);
H->data[0].weight = -1; //可以是0哇???此处为哨兵
return H;
}
bool JudgeQz(string temp, Newtree J) {
int i = 0;
for (; i < temp.length(); i++) {
if (temp[i] == '0') {
if (J->left == NULL) {
Newtree J_1 = new(JNode);
J->left = J_1;
}
else {
if (J->left->Flag == 1) {
return false;
}
}
J = J->left;
}
else
{
if (J->right==NULL)
{
Newtree J_1 = new(JNode);
J->right = J_1;
}
else {
if (J->right->Flag == 1) {
return false;
}
}
J = J->right;
}
}
J->Flag = 1;
if (J->left == NULL && J->right == NULL) //叶子结点
{
return true;
}
else {
return false;
}
}
HuffmanTree DeleteMin(MinHeap H) {
int Parent=0, Child=0;
TreeNode temp;
HuffmanTree MinItem = new TreeNode;
*MinItem = H->data[1]; /* 取出根结点存放的最大值 */
//cout << MinItem.weight << endl;
/* 用最大堆中最后一个元素从根结点开始向上过滤下层结点 */
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++; /* Child指向左右子结点的较小者 */
if (temp.weight <= H->data[Child].weight) break; /* 找到了合适位置 */
else /* 下滤X */
H->data[Parent] = H->data[Child];
}
H->data[Parent] = temp;
return MinItem;
}
void Insert(MinHeap H, HuffmanTree T) {
int i = ++(H->size);
for ( ;H->data[i/2].weight>T->weight; i/=2)
{
H->data[i] = H->data[i / 2];
}
H->data[i] = *T;
//cout << T->weight << endl;
}
HuffmanTree Huffman(MinHeap H) { //构建haffman树
int i;
HuffmanTree T = NULL;
int num = H->size; //size的规模在改变
for (i = 1; i < num; i++) {
T = new TreeNode;
T->left = DeleteMin(H);
T->right = DeleteMin(H);
T->weight = T->left->weight + T->right->weight;
//cout << T->left->weight <<"left"<< T->right->weight << endl;
//cout << T->weight << endl;
Insert(H, T);
}
T = DeleteMin(H);
return T;
}
int WPL(HuffmanTree T, int depth) {
if ((T->left == nullptr) && (T->right == nullptr))
return depth*(T->weight);
else
return (WPL(T->left, depth + 1) + WPL(T->right, depth + 1));
}
MinHeap ReadData(int N, MinHeap H, int Value[]) {
char s = '\0';
int value = 0;
for (int i = 0; i < N; i++) {
cin >> s;
cin >> value;
Value[i] = value;
HuffmanTree T = new(TreeNode);
T->weight = value;
Insert(H, T);
}
return H;
}
int main() {
int N = 0, n = 0;//分别是编码字母的个数和读入的次数
cin >> N;
MinHeap H = createHeap();
int Value[maxn] = {};//
H = ReadData(N, H, Value); //已经建立了最小堆
/*cout<< H->data[1].weight << endl;
cout << H->data[2].weight << endl;
cout << H->data[3].weight << endl;
cout << H->data[4].weight << endl;
cout << H->data[5].weight << endl;
cout << H->data[6].weight << endl;
cout << H->data[7].weight << endl;*/
HuffmanTree T = Huffman(H);
//cout << T->weight;
int wpl = WPL(T,0);
//cout << wpl << endl;
cin >> n;
string temp = "\0";
char c = '\0';
bool result = false;
for (int i = 0; i < n; i++)
{
int coreWpl = 0,flag = 0;
Newtree J = new JNode;
for (int j = 0; j < N; j++)
{
cin >> c>> temp;
if (temp.length() > N - 1) result = false;
coreWpl += temp.length()*Value[j];
if (flag==0)
{
result = JudgeQz(temp, J);
if (result==false)
{
flag = 1;
}
}
}
delete J;
//cout << coreWpl << endl;
if (result && (coreWpl == wpl))
{
cout << "Yes" << endl;
}
else {
cout << "No" << endl;
}
}
system("pause");
return 0;
}