05-树8. Huffman Codes (30)

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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值