• 哈夫曼编码的实现


    实现方案:

    1. 建立哈夫曼树

    (1)统计各个字符出现次数,按次数从小到大的顺序生成队列;

    (2)每次获取队列前两个节点(即队列中字符出现次数最少的两个),同时队头前移两位,将它们的字符出现次数相加,得到一个新节点,插入到队列合适位置;

    (3)当队列中仅剩一个节点时,哈夫曼树构造完毕,该节点即为树的根节点。

    2. 建立哈夫曼编码表

    (1)从哈夫曼树根开始遍历,遍历结束的同时编码表也构造完成,整个过程用递归实现,注意结束条件为遍历到叶子节点;

    (2)如果当时节点的左孩子不为空,则code[k]='0',递归遍历其左子树;

    (3)如果当时节点的右孩子不为空,则code[k]='1',递归遍历其右子树;

    (4)如果当时节点为叶子,则code[k]='',构造新的编码表节点,并将其插入编码表。

    3. 将字符串和哈夫曼编码互换,测试

    代码如下,时常翻看,细细揣摩,大有裨益:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define MAX_SZ 256
    #define TYPE htNode *
    
    // 哈夫曼树节点
    typedef struct htNode{
        char symbol;
        struct htNode *left;
        struct htNode *right;
    }htNode;
    
    // 哈夫曼树
    typedef struct htTree{
        htNode *root;
    }htTree;
    
    // 队列节点
    typedef struct pQueueNode{
        TYPE val;
        unsigned int priority;
        struct pQueueNode *next;
    }pQueueNode;
    
    // 队列
    typedef struct pQueue{
        unsigned int size;        // 队列长度
        pQueueNode *first;        // 头指针
    }pQueue;
    
    // 字符编码节点
    typedef struct hlNode{
        char symbol;
        char *code;
        struct hlNode *next;
    }hlNode;
    
    // 字符编码表
    typedef struct hlTable{
        hlNode *first;
        hlNode *last;
    }hlTable;
    
    // 初始化哈夫曼队列
    void initpQueue(pQueue **q)
    {
        (*q) = (pQueue *)malloc(sizeof(pQueue));
        (*q)->first = NULL;
        (*q)->size = 0;
        return;
    }
    
    // 插入队列
    void addpQueue(pQueue **q,TYPE val,unsigned int priority)
    {
        if ((*q)->size == MAX_SZ){
            printf("Queue is full.
    ");
            return;
        }
    
        pQueueNode *aux = (pQueueNode *)malloc(sizeof(pQueueNode));
        aux->priority = priority;
        aux->val = val;
    
        if ((*q)->first == NULL || (*q)->size == 0){    // 队列为空
            aux->next = NULL;
            (*q)->first = aux;
            (*q)->size = 1;
        }
        else{
            // 小于第一个节点
            if (priority <= (*q)->first->priority){
                aux->next = (*q)->first;
                (*q)->first = aux;
                (*q)->size++;
                return;
            }
    
            // 迭代
            else{
                pQueueNode *iterator = (*q)->first;
                while(iterator->next != NULL){
                    if (priority <= iterator->next->priority){
                        aux->next = iterator->next;
                        iterator->next = aux;
                        (*q)->size++;
                        return;
                    }
                    iterator = iterator->next;
                }
    
                // 比队列里所有的都大
                if (iterator->next == NULL){
                    aux->next = NULL;
                    iterator->next = aux;
                    (*q)->size++;
                    return;
                }
            }        
        }
    }
    
    // 从队列中获取节点
    TYPE getpQueue(pQueue **q)
    {
        TYPE returnVal;
        if ((*q)->size > 0){
            returnVal = (*q)->first->val;
            (*q)->first = (*q)->first->next;
            (*q)->size --;
        }
        else{
            printf("Queue is empty.
    ");
        }
        return returnVal;
    }
    
    htTree *buildTree(char *inputString)
    {
        // 256个指针记录256个ASCII码出现的次数
        int *probability = (int *)malloc(sizeof(int)*256);
    
        // 初始化
        for (int i=0; i<256; i++){
            probability[i] = 0;
        }
    
        // 统计待编码的字符串各个字符出现的次数
        for (int j=0; inputString[j]!=''; j++){
            probability[inputString[j]]++;
        }
    
        // pQueue队列头指针
        pQueue *huffmanQueue;
        initpQueue(&huffmanQueue);
    
        // 填充队列
        for (int k=0; k<256; k++){
            if (probability[k] != 0){
                htNode *aux = (htNode *)malloc(sizeof(htNode));
                aux->left = NULL;
                aux->right = NULL;
                aux->symbol = (char)k;
                addpQueue(&huffmanQueue,aux,probability[k]);
            }
        }
        free(probability);
    
        // 生成哈夫曼树
        while(huffmanQueue->size != 1){
            int pri;
            pri = huffmanQueue->first->priority;
            pri += huffmanQueue->first->next->priority;
    
            htNode *left = getpQueue(&huffmanQueue);
            htNode *right = getpQueue(&huffmanQueue);
    
            htNode *newNode = (htNode *)malloc(sizeof(htNode));
            newNode->left = left;
            newNode->right = right;
            newNode->symbol = pri+'0';
            
            addpQueue(&huffmanQueue,newNode,pri);
        }
        htTree *tree = (htTree *)malloc(sizeof(htTree));
        tree->root = getpQueue(&huffmanQueue);
        return tree;
    }
    
    // 前序遍历
    void pre_sequence(htNode *t)
    {
        if(t == NULL){
            return;
        }
        printf("%c",t->symbol);
        pre_sequence(t->left);
        pre_sequence(t->right);
    }
    
    void traverseTree(htNode *treeNode, hlTable **table, int k, char code[256])
    {
        // 叶子节点
        if (treeNode->left == NULL && treeNode->right == NULL){
            code[k] = '';
            hlNode *aux = (hlNode *)malloc(sizeof(hlNode));
            aux->symbol = treeNode->symbol;
            aux->next = NULL;
            aux->code = (char *)malloc(sizeof(char)*(strlen(code)+1));
            strcpy(aux->code,code);
    
            if ((*table)->first == NULL){
                (*table)->first = (*table)->last = aux;
            }
            else{
                (*table)->last->next = aux;
                (*table)->last = aux;
            }
        }
    
        if (treeNode->left != NULL){
            code[k] = '0';
            traverseTree(treeNode->left,table,k+1,code);
        }
        if (treeNode->right != NULL){ 
            code[k] = '1';
            traverseTree(treeNode->right,table,k+1,code);
        }
    }
    
    hlTable *buildTable(htTree *huffmanTree)
    {
        hlTable *table = (hlTable *)malloc(sizeof(hlTable));
        table->first = NULL;
        table->last = NULL;
        
        char code[256];    // 编码
        int k = 0;    // 层数
    
        // 关键是这个函数
        traverseTree(huffmanTree->root,&table,k,code);
        return table;
    }
    
    // 将字符串转换为哈夫曼编码
    void encode(hlTable *table, char *input)
    {
        hlNode *iterator;
        printf("Encode:
    ");
    
        printf("Before encode:");
        puts(input);
    
        printf("After encode:");
        for (int i=0; input[i] != ''; i++){
            iterator = table->first;
            while(iterator->symbol != input[i]){
                iterator = iterator->next;
            }
            printf("%s",iterator->code);
        }
        printf("
    ");
    }
    
    // 将哈夫曼编码转换为字符串
    void decode(htTree *tree, char *input)
    {
        htNode *iterator;
        iterator = tree->root;
        printf("Decode:
    ");
    
        printf("Before Decode:");
        puts(input);
    
        printf("After Decode:");
        for (int i=0; input[i] != ''; i++){
            // 到达叶子节点
            if (iterator->left == NULL && iterator->right == NULL){
                printf("%c",iterator->symbol);
                iterator = tree->root;
            }
    
            if (input[i] == '0'){
                iterator = iterator->left;
            }
            if (input[i] == '1'){
                iterator = iterator->right;
            }
        }
        printf("
    ");
    }
    
    int main()
    {
        // 建立哈夫曼树
        htTree *codeTree = buildTree("I love FishC.com!");
        pre_sequence(codeTree->root);
        printf("
    ");
    
        // 建立哈夫曼编码表
        hlTable *codeTable = buildTable(codeTree);
    
        // 将字符串转换成哈夫曼编码
        encode(codeTable,"I love FishC.com!");
    
        // 将哈夫曼编码转换成字符串
        decode(codeTree,"001111100011");
    
        return 0;
    }

    测试结果:

  • 相关阅读:
    [bzoj1613 Usaco2007 Jan]Running贝茜的晨练计划
    [bzoj1600][Usaco2008 Oct]建造栅栏
    [bzoj3208]花神的秒题计划I
    [vijos1011]滑雪
    [noip2007 pjt3] 守望者的逃离
    DP(1) 背包
    快速幂 模板及应用
    BZOJ1303: [CQOI2009]中位数图
    BZOJ1083: [SCOI2005]繁忙的都市
    Bzoj1084: [SCOI2005]最大子矩阵
  • 原文地址:https://www.cnblogs.com/raul-ac/p/3254204.html
Copyright © 2020-2023  润新知