美文网首页
哈夫曼编码

哈夫曼编码

作者: 大橘猪猪侠 | 来源:发表于2020-04-28 15:36 被阅读0次

    哈夫曼编码是一种编码方式,该方法依据字符出现概率来构造异字头的平均长度最短的码字,一般就叫做Huffman编码。

    哈夫曼思想就是依据使用的频率来最大化的节省字符存储空间。

    图1.png

    图1是我们求一个分数属于那个阶段的流程判断图

    图2.png

    图2是利用哈夫曼思想来画出的流程图

    我们通过两种方式去求D节点的路程长度值:

    图3.png 图4.png

    图3和图4是两种方式求的路程值的示意图,从两图中可以很好的得出两种方式哪一种更好。

    下面我们通过代码的方式来实现哈夫曼。

    1、首先先进行一些基本的变量和结构体设置

    const int MaxValue = 10000;//初始设定的权值最大值
    const int MaxBit = 4;//初始设定的最大编码位数
    const int MaxPoint = 10;//初始设定的最大结点个数
    
    typedef struct HaffNode{
        int weight;
        int flag;
        int parent;
        int leftChild;
        int rightChild;
    }HaffNode;
    
    //存放哈夫曼编码的数据元素结构
    typedef struct Code{
        int bit[MaxBit];//数组
        int start;//编码的起始下标
        int weight;//字符的权值
    }Code;
    

    2、根据权重值,构建哈夫曼树
    构建哈夫曼树,先对哈夫曼树进行初始化,由于一些值是由后面两个值相加而存在的节点;因此,我们可以知道数组中拥有的权重值都是叶子节点,根据二叉树原理,可以得到总节点数。
    对权重数组进行遍历,找出最小的两个节点,并用一个变量标记值是否有被使用,来得到哈夫曼树

    void Haffman(int weight[],int n,HaffNode *haffTree){
        int m1,m2,x1,x2;
        //哈夫曼树初始化
        //n个叶子节点,2n-1个数
        for(int i = 0;i < 2*n-1 ; i++){
            if(i<n)
                haffTree[i].weight = weight[i];
            else
                haffTree[i].weight = 0;
    
            haffTree[i].parent = 0;
            haffTree[i].flag = 0;
            haffTree[i].leftChild = -1;
            haffTree[i].rightChild = -1;
        }
        
    
        //构造哈夫曼树的n-1个非叶子节点
        for (int i = 0; i<n-1; i++) {
            m1 = m2 = MaxValue;
            x1=x2=0;
            for (int j = 0; j<n+i; j++) {
                if(haffTree[j].weight<m1&&haffTree[j].flag == 0){
                    m2=m1;
                    x2=x1;
                    m1=haffTree[j].weight;
                    x1=j;
                }else if(haffTree[j].weight<m2&&haffTree[j].flag == 0){
                    m2 = haffTree[j].weight;
                    x2=j;
                }
            }
            //找出两颗权值最小的子树合并为一颗子树
            haffTree[x1].parent = n+i;
            haffTree[x2].parent = n+i;
            //将两个节点的flag标记为1,表示已经加入到哈夫曼树中
            haffTree[x1].flag = 1;
            haffTree[x2].flag = 1;
            //修改节点n+i节点的权值
            haffTree[n+i].weight = haffTree[x1].weight + haffTree[x2].weight;
            //修改n+i的左右孩子值
            haffTree[n+i].leftChild = x1;
            haffTree[n+i].rightChild = x2;
        }
    }
    

    3、创建哈夫曼编码元素结构,记录每个节点字符的权重值和编码下标值
    由于得到的下标值是逆序的,所有需要对下标值进行逆序置换。

    //2、哈夫曼编码
    //由n个节点的哈夫曼树haffTree构造的哈夫曼编码haffCode
    void HaffmanCode(HaffNode haffTree[],int n,Code haffCode[]){
        //1、创建一个节点cd
        Code *cd = (Code *)malloc(sizeof(Code));
        int child,parent;
        //2、求n个叶子节点的哈夫曼编码
        for (int i = 0; i<n; i++) {
            //从0开始计数
            cd->start = 0;
            //取得编码对应权值的字符
            cd->weight = haffTree[i].weight;
            //当叶子节点i为孩子节点
            child = i;
            //找到child的双亲节点
            parent = haffTree[child].parent;
            //由叶节点向上直到根节点
            while (parent!=0) {
                if(haffTree[parent].leftChild == child){
                    cd->bit[cd->start] = 0;//左孩子节点编码0
                }else{
                    cd->bit[cd->start] = 1;//右孩子节点编码1
                }
                //编码自增
                cd->start++;
                //当前双亲节点成为孩子节点
                child = parent;
                //找到双亲节点
                parent = haffTree[child].parent;
            }
            int temp = 0;
            for (int j = cd->start-1; j>=0; j--) {
                temp = cd->start-j-1;
                haffCode[i].bit[temp] = cd->bit[j];
            }
            //把cd中的数据赋值到haffCode[i]中
            //保存好haffCode的起始位以及权重值
            haffCode[i].start = cd->start;
            //保存编码对应的权值
            haffCode[i].weight = cd->weight;
    
        }
    }
    
    

    main函数

    
    printf("哈夫曼编码!\n");
        int n=6,m = 0;
        //权值
        //
        int weight[] = {2,4,6,8,1,9};
        //初始化哈夫曼树,哈夫曼编码
        HaffNode *haffTree = malloc(sizeof(HaffNode)*2*n-1);
        Code *haffCode = malloc(sizeof(Code)*n);
        
        //当前n>MaxN越界,无法处理
        if(n>MaxPoint){
            printf("定义的n越界,修改MaxPoint");
            exit(0);
        }
        //1、构建哈夫曼树
        Haffman(weight, n, haffTree);
        //2、根据哈夫曼树得到哈夫曼编码
        HaffmanCode(haffTree, n, haffCode);
        //3、打印权值
        for (int i = 0; i<n; i++) {
            printf("weight = %d\n",haffCode[i].weight);
            for (int j = 0; j<haffCode[i].start; j++) {
                printf("%d",haffCode[i].bit[j]);
            }
            m = m+haffCode[i].weight*haffCode[i].start;
            printf("\n");
        }
        printf("总哈夫曼值为:%d\n",m);
    
    

    打印结果:


    15880592087214.png

    相关文章

      网友评论

          本文标题:哈夫曼编码

          本文链接:https://www.haomeiwen.com/subject/fxzvwhtx.html