Implementación del lenguaje C de codificación HuffMan

Implementación del lenguaje C de codificación HuffMan

Se realizan un método de codificación y dos métodos de decodificación.
La decodificación utiliza las hojas retrocediendo hasta la raíz.
Uno usa el proceso transversal desde la raíz.

código:

HuffManCodificación

//
// Created by Zza on 2022/4/23.
//

#ifndef DATASTRUCTUREIMPLEMENTINGC_HUFFMANTREEENCODING_H
#define DATASTRUCTUREIMPLEMENTINGC_HUFFMANTREEENCODING_H

#include <stdlib.h>
#include <errno.h>
#include <math.h>
#include "../../Chapter4/String.h"

typedef struct node{
    
    
    char tar;
    int freq;
} node;

#ifndef ELEM
#define ELEM
typedef node ELEMENT_TYPE;
#endif

#include "../Binary Tree/BinaryTree_Array.h"

typedef struct HuffManTree{
    
    
//    实际上这里应该自己再重新设置一个
    Bin_Tree_Arr trees;
    int curTop;
    int treeNums;
    int* roots;
    bool encoded;
}HuffManTree;

typedef struct InitDataPackage{
    
    
    int n;
    node* init;
} pkg;

bool DisplayHuffManStruct(HuffManTree*);

__attribute__((unused)) bool PkgDestruct(pkg*);

__attribute__((unused)) bool Init_HuffMan(HuffManTree* tar, pkg* info);

__attribute__((unused)) bool HuffManEncoding(HuffManTree* tar);

bool HuffManDestruct(HuffManTree *tar);

//======================================================================================================================

bool _find_two_min_tree(HuffManTree* tar, int *min1, int *min2);

bool _tree_merge(HuffManTree* tar, int root1, int root2);

//======================================================================================================================

__attribute__((unused)) bool HuffManEncoding(HuffManTree* tar){
    
    
    int timer = tar->treeNums - 1;
    int cur_tree_l, cur_tree_r;
    while (timer--){
    
    
//        找到最小的两个树,在roots中的位置
        _find_two_min_tree(tar,&cur_tree_l,&cur_tree_r);
//        认为左结点会比右结点小,将树拼接,然后结点坐标存在roots的右边
        _tree_merge(tar,cur_tree_l,cur_tree_r);
    }
    return true;
}

__attribute__((unused)) bool Init_HuffMan(HuffManTree* tar, pkg* info){
    
    
    tar->trees = (Binary_Tree_Array*)malloc(sizeof(Binary_Tree_Array));
    BinStaticTree_init(tar->trees, 2*info->n-1);
    tar->treeNums = tar->curTop = tar->trees->cur =info->n;
    tar->roots = (int*) malloc(sizeof(int)*info->n);
    for(int i=0;i<info->n;i++){
    
    
        tar->trees->elems[i].data = info->init[i];
        tar->trees->elems[i].left = tar->trees->elems[i].right = -1;
        tar->roots[i]=i;
    }
    tar->encoded = false;
    return true;
}

//======================================================================================================================

bool _find_two_min_tree(HuffManTree* tar, int *min1, int *min2){
    
    
//    由于我们算法的设计,我们认为,0号位置一定会在交归纳中是最后一个树的根,用这个来预设
    *min1 = *min2 = 0;
    int temp;
//    root负责记录是树根的结点位置
    for(int i=1, j=0;i < tar->treeNums;i++){
    
    
        temp = tar->roots[i];
        if(temp>=0){
    
    
            temp = tar->trees->elems[temp].data.freq;
            if(temp <= tar->trees->elems[tar->roots[*min2]].data.freq){
    
    
                if(temp < tar->trees->elems[tar->roots[*min1]].data.freq){
    
    
                    *min2 = *min1;
                    *min1 = i;
                } else{
    
    
                    *min2 = i;
                }
            }
        }
    }
    return true;
}

bool _tree_merge(HuffManTree* tar, int root_l, int root_r){
    
    
    node l, r, cur;

    l = tar->trees->elems[tar->roots[root_l]].data;
    r = tar->trees->elems[tar->roots[root_r]].data;

    tar->trees->elems[tar->roots[root_l]].parent = tar->trees->elems[tar->roots[root_r]].parent = tar->curTop;

//    printf("merge %d,%d at %d,%d\n",root_l,root_r,tar->roots[root_l],tar->roots[root_r]);
//    printf("with char: %c,%c\n",l.tar,r.tar);
//    printf("with freq: %d,%d\n",l.freq,r.freq);

    _StaticNode temp = {
    
    {
    
    's',l.freq + r.freq},tar->roots[root_l], tar->roots[root_r]};
    
    tar->trees->elems[tar->curTop] = temp;

    tar->roots[root_l] = tar->curTop;
    tar->roots[root_r] = -1;

    tar->curTop++;
    return true;
}

bool HuffManDestruct(HuffManTree *tar){
    
    
    BinStaticTree_destruct(tar->trees);
    free(tar->trees);
    free(tar->roots);
}



#endif //DATASTRUCTUREIMPLEMENTINGC_HUFFMANTREEENCODING_H

HuffManDecodificación

//
// Created by Zza on 2022/4/23.
//

#ifndef DATASTRUCTUREIMPLEMENTINGC_HUFFMANTREEDECODING_H
#define DATASTRUCTUREIMPLEMENTINGC_HUFFMANTREEDECODING_H

#include "./HuffManTreeEncoding.h"
#include <stdio.h>

#define HUFFMAN_CODE_NUMS 26
#define HUFFMAN_CODE_BASE_CHAR 'a'

typedef struct ResContainer{
    
    
    char* res[HUFFMAN_CODE_NUMS];
}ResContainer;

bool ContainerDestruct(ResContainer*);

bool DisplayContainer(ResContainer*);

__attribute__((unused)) bool HuffManDecode_Display_Stack(HuffManTree* tar, int root);

bool HuffManDecode_Reverse(HuffManTree* tar, ResContainer*);

#ifndef TREE_STK
#define TREE_STK
typedef int tNode;
#endif

bool DisplayAct(char*, int, char);

// 我们应当好好利用哈夫曼树是一个完全二叉树的性质来进行解码
__attribute__((unused)) bool HuffManDecode_Display_Stack(HuffManTree* tar, int root){
    
    
    Bin_Tree_Arr obj = tar->trees;
//    设置两个栈,一个栈用来存我们的行动路径,一个栈拿来存上一个根节点

    char* routine = (char*) malloc(sizeof(char)*obj->cur);
    int* nodes = (int*) malloc(sizeof(int)*obj->cur);

    char act;

    int i = 0, n = tar->treeNums;
//    总共访问n个叶子
    while (n){
    
    
//        向左下搜索到最下方

        printf("-----------------------\n"
               "left searching, start root %d l:%d r:%d\n",
               root,obj->elems[root].left,obj->elems[root].right);

        while (root>=0 && obj->elems[root].left >= 0){
    
    
            printf("%d-",root);
            nodes[i] = root;
            routine[i++] = '0';
            root = obj->elems[root].left;
        }
//        显示当前编码路径
        DisplayAct(routine,i,obj->elems[root].data.tar);
        n--;

//        向上退栈
// 首先,我们在路径栈中,存放的是我们以什么方式来到这个节点
// 如果我们是由向右操作,进入节点的话,说明我们已经访问过这个根的子树,应当再次向上
        do {
    
    
            if(!i)break;
            root = nodes[--i];
            act = routine[i];

//            printf("trace back,act:%c, cur root %d l:%d r:%d\n",act,root,obj->elems[root].left,obj->elems[root].right);

            //            每次路径退栈,也是反映我们是从左还是右回溯进入根的
        }while (act == '1');
//        当我们一直向上走,如果我们是从左进入根时,认为左树遍历完成,我们就会退出循环,去访问右边
//        向右移动一次

        root = obj->elems[root].right;
        nodes[i] = root;
        routine[i++] = '1';

//        printf("right move, cur root %d l:%d r:%d\n",
//               root,obj->elems[root].left,obj->elems[root].right);

    }
    return true;
}

bool HuffManDecode_Reverse(HuffManTree* tar, ResContainer* container){
    
    
    int cur,temp,base;
    for(int i=0;i<tar->treeNums;i++){
    
    
        cur = i;
        container->res[i] = (char*) malloc(sizeof(char)*tar->treeNums);
        base = tar->treeNums;
        container->res[i][--base] = '\0';
        while (tar->trees->elems[cur].parent){
    
    
            temp = tar->trees->elems[cur].parent;
            container->res[i][--base] = (cur==tar->trees->elems[temp].left)?'0':'1';
            cur = temp;
        }
        container->res[i][0] = (char)--base;
    }
    return true;
}

bool DisplayAct(char* tar, int len, char type){
    
    
    printf("huffman code %c:",type);
    for(int i=0;i<len;i++){
    
    
        printf("%c",*tar);
        tar++;
    }
    printf("\n");
}

bool ContainerDestruct(ResContainer* tar){
    
    
    for (int i = 0; i < HUFFMAN_CODE_NUMS; ++i) {
    
    
        free(tar->res[i]);
    }
    return true;
}

bool DisplayContainer(ResContainer* tar){
    
    
    for (int i = 0; i < HUFFMAN_CODE_NUMS; ++i) {
    
    
        printf("%c: %s\n",i+HUFFMAN_CODE_BASE_CHAR,&(tar->res[i][(tar->res[i][0])+1]));
    }
    return true;
}

#endif //DATASTRUCTUREIMPLEMENTINGC_HUFFMANTREEDECODING_H

Envoltura de HuffMan

//
// Created by Zza on 2022/4/25.
//

#ifndef DATASTRUCTUREIMPLEMENTINGC_HUFFMANTREE_H
#define DATASTRUCTUREIMPLEMENTINGC_HUFFMANTREE_H

#include "HuffManTreeEncoding.h"
#include "HuffManTreeDecoding.h"
#include <stdio.h>

bool CalcCharFreq(const char* tar, pkg* res){
    
    
    int map[HUFFMAN_CODE_NUMS];
    for(int i=0;i<HUFFMAN_CODE_NUMS;i++){
    
    
        map[i] = 0;
    }
    while (*tar){
    
    
        map[(int)*tar-HUFFMAN_CODE_BASE_CHAR]++;
        tar++;
    }
    res->init = (node*)malloc(sizeof(node)*HUFFMAN_CODE_NUMS);
    res->n = HUFFMAN_CODE_NUMS;
    for(int i=0;i<HUFFMAN_CODE_NUMS;i++){
    
    
        res->init[i].tar = (char)(i+HUFFMAN_CODE_BASE_CHAR);
        res->init[i].freq = map[i];
    }
    return true;
}

__attribute__((unused)) bool PkgDestruct(pkg* tar){
    
    
    free(tar->init);
    return true;
}

bool HuffManDisplay(const char* tar){
    
    
    pkg info;
    CalcCharFreq(tar,&info);

    HuffManTree obj;
    Init_HuffMan(&obj,&info);
    HuffManEncoding(&obj);
    DisplayHuffManStruct(&obj);

    ResContainer container;
    HuffManDecode_Reverse(&obj, &container);
    DisplayContainer(&container);

    HuffManDecode_Display_Stack(&obj, obj.curTop-1);


    ContainerDestruct(&container);
    HuffManDestruct(&obj);
    PkgDestruct(&info);
    return true;
}

bool DisplayHuffManStruct(HuffManTree* tar){
    
    
    for(int i=0;i<tar->curTop;i++){
    
    
        _StaticNode temp = tar->trees->elems[i];
        printf("id: %d\t"
               "char: %c\t"
               "freq: %d\t"
               "left: %d\t"
               "right: %d\t"
               "parent: %d\n",i,
               temp.data.tar,temp.data.freq,temp.left,temp.right,temp.parent);
    }
    return true;
}

#endif //DATASTRUCTUREIMPLEMENTINGC_HUFFMANTREE_H

Supongo que te gusta

Origin blog.csdn.net/interval_package/article/details/124538080
Recomendado
Clasificación