http://www.patest.cn/contests/mooc-ds2015spring/05-%E6%A0%918
思路:
首先按给定的字符的频率和编码来构建一棵哈夫曼树
构建完成之后判断 1.编码最后一位所在的节点是否存在孩子 2. 是否有不同的编码的最后一位占据了相同的节点 3. 是否存在节点只有一个孩子 4. 如果上述错误情况都未出现,那么计算给定的编码的总权重,然后再按给定的字符频率构建一棵正确的哈夫曼树,比较二者的总权重是否相同。 同时考虑在输入字符对应编码时不按输入字符的频率时的顺序来输入。
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <cmath>
struct HuffmanTree
{
int weight;
HuffmanTree* left;
HuffmanTree* right;
};
HuffmanTree* CreateHuffman()
{
HuffmanTree* huffman = (HuffmanTree*) malloc(sizeof(HuffmanTree));
huffman->weight = 0;
huffman->left = NULL;
huffman->right = NULL;
return huffman;
}
struct MinHeap
{
HuffmanTree** data;
int size;
int capacity;
};
const int MINSIZE = -1;
MinHeap* CreateMinHeap(int maxSize)
{
MinHeap* heap = (MinHeap*) malloc(sizeof(MinHeap));
heap->data = (HuffmanTree**) malloc(sizeof(HuffmanTree*) * (maxSize + 1));
for (int i = 0; i <= maxSize; i++)
{
heap->data[i] = (HuffmanTree*) malloc(sizeof(HuffmanTree));
heap->data[i]->left = NULL;
heap->data[i]->right = NULL;
heap->data[i]->weight = 0;
}
heap->size = 0;
heap->capacity = maxSize;
heap->data[0]->weight = MINSIZE;
return heap;
}
MinHeap* BuildMinHeap(MinHeap* heap)
{
// 这里假设所有H->size个元素已经存在H->data[]->weight中
int i = heap->size / 2;
int parent = i;
int child = 0;
int temp = 0;
for (; i > 0; i--)
{
temp = heap->data[i]->weight;
for (parent = i; parent * 2 <= heap->size; parent = child)
{
child = parent * 2;
if ((child != heap->size) && (heap->data[child]->weight > heap->data[child + 1]->weight))
{
child++;
}
if (temp <= heap->data[child]->weight)
{
break;
}
else
{
heap->data[parent]->weight = heap->data[child]->weight;
}
}
heap->data[parent]->weight = temp;
}
return heap;
}
HuffmanTree* DeleteMinHeap(MinHeap* heap)
{
if (heap->size == 0)
{
printf("Heap is EMPTY.\n");
return NULL;
}
HuffmanTree* const lastNode = heap->data[heap->size];
heap->size--;
HuffmanTree* const deletedNode = heap->data[1];
int parent = 1;
int child = 2;
for (; parent * 2 <= heap->size; parent = child)
{
child = parent * 2;
if (child != heap->size && heap->data[child]->weight > heap->data[child + 1]->weight)
{
child++;
}
if (lastNode->weight > heap->data[child]->weight)
{
heap->data[parent] = heap->data[child];
}
else
{
break;
}
}
heap->data[parent] = lastNode;
return deletedNode;
}
void InsertMinHeap(MinHeap* heap, HuffmanTree* huffman)
{
if (heap->size == heap->capacity)
{
printf("Heap is FULL.\n");
return;
}
int item = huffman->weight;
heap->size++;
int i = heap->size;
for(; heap->data[i / 2]->weight > item; i /= 2)
{
heap->data[i] = heap->data[i / 2];
}
heap->data[i] = huffman;
}
HuffmanTree* BuildHuffman(MinHeap* heap)
{
HuffmanTree* huffman;
BuildMinHeap(heap);
const int SIZE = heap->size;
for (int i = 1; i < SIZE; i++)
{
huffman = CreateHuffman();
huffman->left = DeleteMinHeap(heap);
huffman->right = DeleteMinHeap(heap);
huffman->weight = huffman->left->weight + huffman->right->weight;
InsertMinHeap(heap, huffman);
}
return heap->data[1];
}
typedef HuffmanTree* QueueType;
struct QNode
{
QueueType data;
QNode* next;
};
struct LinkQueue
{
QNode* rear;
QNode* front;
};
bool IsEmptyQ(LinkQueue* queue)
{
return (queue->front == NULL);
}
LinkQueue* CreateQueue()
{
LinkQueue* queue = (LinkQueue*) malloc(sizeof(LinkQueue));
queue->front = NULL;
queue->rear = NULL;
return queue;
}
void AddQ(LinkQueue* p, QueueType const item)
{
if (p->front == NULL)
{
QNode* newNode = (QNode*) malloc(sizeof(QNode));
newNode->data = item;
newNode->next = NULL;
p->front = newNode;
p->rear = newNode;
return;
}
QNode* newNode = (QNode*) malloc(sizeof(QNode));
newNode->data = item;
newNode->next = NULL;
p->rear->next = newNode;
p->rear = newNode;
}
QueueType DeleteQ(LinkQueue* p)
{
if (p->front == NULL)
{
printf("Queue is empty.");
return NULL;
}
QNode* temp = p->front;
if (p->front == p->rear)
{
p->front = NULL;
p->rear = NULL;
QueueType item = temp->data;
free(temp);
return item;
}
p->front = p->front->next;
QueueType item = temp->data;
free(temp);
return item;
}
const int MAXSIZE = 1000;
const int MAXBIT = 1000;
int main(void)
{
// 输入
int count_Character;
scanf("%d", &count_Character);
char character[MAXSIZE];
int charWeight[MAXSIZE];
char charCode[MAXSIZE][MAXBIT];
int length_Code[MAXSIZE];
int ascII[MAXSIZE];
for (int i = 1; i <= count_Character; i++)
{
getchar();
scanf("%c", &character[i]);
int temp = (int)character[i];
ascII[temp] = i;
scanf("%d", &charWeight[i]);
}
int count_Case;
scanf("%d", &count_Case);
bool result[MAXSIZE];
for (int i = 0; i < count_Case; i++)
{
result[i] = true;
}
int totalInputBit[MAXSIZE];
for (int i = 0; i < MAXSIZE; i++)
{
totalInputBit[i] = 0;
}
// M个case,每个case的结果是result的一个元素
for (int M = 0; M < count_Case; M++)
{
HuffmanTree* codeTree = CreateHuffman();
HuffmanTree* currentNode;
// 遍历每个字母,判断是否存在前缀编码并计算总权重
for (int i = 1; i <= count_Character; i++)
{
currentNode = codeTree;
getchar();
char temp;
scanf("%c", &temp);
int index = ascII[(int)temp];
getchar();
scanf("%s", charCode[index]);
length_Code[index] = strlen(charCode[index]);
// 一位一位地建树,判断是否存在前缀编码
for (int j = 0; j < length_Code[index]; j++)
{
HuffmanTree** childNode;
if (charCode[index][j] == '0') // 当前位是0
{
childNode = &(currentNode->left);
}
else // 当前位是1
{
childNode = &(currentNode->right); // 防止代码重复采用地址指针
}
// 如果节点不存在则创建
if ((*childNode) == NULL)
{
(*childNode) = CreateHuffman();
}
// 如果路径上有节点的权重是-1或-2,则置错误标志-2
if ((*childNode)->weight == -1 || (*childNode)->weight == -2)
{
(*childNode)->weight = -2;
}
else
{
// 如果该节点是最后一位,则该节点权重置-1
if (j == length_Code[index] - 1)
{
(*childNode)->weight = -1;
}
// 否则置0
else
{
(*childNode)->weight = 0;
}
}
/*
// 如果该节点是最后一位,那么权重置-1
if (j == length_Code[index] - 1)
{
// 如果该节点权重已经是-1,那么说明出现了两个相同的编码,置错误标志-2
if ((*childNode)->weight == -1 || (*childNode)->weight == -2)
{
(*childNode)->weight = -2;
}
else
{
(*childNode)->weight = -1;
}
}
// 如果该节点还不是最后一位,那么该节点权重置0
else
{
// 如果该节点权重不是-1,则节点权重置0
if ((*childNode)->weight == -1 || (*childNode)->weight == -2)
{
(*childNode)->weight = -2;
}
}
*/
currentNode = *childNode;
}
// 每一个字母的权重和字长计入该case总长
totalInputBit[M] += length_Code[index] * charWeight[index];
}
LinkQueue* binQueue = CreateQueue();
AddQ(binQueue, codeTree);
HuffmanTree* tempBinNode = NULL;
while (!IsEmptyQ(binQueue))
{
tempBinNode = DeleteQ(binQueue);
if (tempBinNode->weight == -1 && (tempBinNode->left != NULL || tempBinNode->right != NULL))
{
result[M] = false;
break;
}
if (tempBinNode->weight == -2)
{
result[M] = false;
break;
}
// 判断是否有节点只有一个儿子
if ((tempBinNode->left == NULL && tempBinNode->right != NULL) ||
(tempBinNode->right == NULL && tempBinNode->left != NULL))
{
result[M] = false;
//printf("NO : JUST HAVE A CHILD\n");
break;
}
if (tempBinNode->left != NULL)
{
AddQ(binQueue, tempBinNode->left);
}
if (tempBinNode->right != NULL)
{
AddQ(binQueue, tempBinNode->right);
}
}
}
MinHeap* testHeap = CreateMinHeap(count_Character);
testHeap->size = count_Character;
for (int i = 1; i <= count_Character; i++)
{
testHeap->data[i]->weight = charWeight[i];
}
HuffmanTree* codeTreeHead = BuildHuffman(testHeap);
LinkQueue* queue = CreateQueue();
AddQ(queue, codeTreeHead);
int height = 0;
int currentNode = 1;
int nextNode = 0;
int totalTreeBit = 0;
HuffmanTree* tempNode = NULL;
while (!IsEmptyQ(queue))
{
// 计算每个字符的高度
tempNode = DeleteQ(queue);
currentNode--;
if (tempNode->left != NULL)
{
nextNode += 2;
}
else
{
totalTreeBit += tempNode->weight * height;
}
if (tempNode->left != NULL)
{
AddQ(queue, tempNode->left);
AddQ(queue, tempNode->right);
}
if (currentNode == 0)
{
height++;
currentNode = nextNode;
nextNode = 0;
}
}
// 输出
for (int i = 0; i < count_Case; i++)
{
if (result[i] == false)
{
continue;
}
else
{
if (totalInputBit[i] != totalTreeBit)
{
result[i] = false;
}
}
}
for (int i = 0; i < count_Case; i++)
{
if (result[i] == false)
{
printf("No\n");
}
else
{
printf("Yes\n");
}
}
return 0;
}