zoukankan      html  css  js  c++  java
  • 哈夫曼树与哈夫曼编码

    2018-03-02 15:03:37

    编码问题是计算机科学乃至EE中的一个核心的问题,最基础的编码方式是采用等长的编码,比如计算机中的字符的编码就是采用等长的8位,即一个字节进行的编码。

    但是在实际生活中,每个字符出现的频率是不同的,因此,如果我们采用不等长编码,将出现频率高的字符采用较短的编码,对出现频率低的字符采用较长的编码,就可以实现更高效和节省的编码。

    一、哈夫曼树

    霍夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。树的路径长度是从树根到每一结点的路径长度之和,记为WPL=(W1*L1+W2*L2+W3*L3+...+Wn*Ln),N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,...n)。可以证明霍夫曼树的WPL是最小的。

    1951年,霍夫曼和他在MIT信息论的同学得选择是完成学期报告还是期末考试。导师罗伯特·法诺出的学期报告题目是,查找最有效的二进制编码。由于无法证明哪个已有编码是最有效的,霍夫曼放弃对已有编码的研究,转向新的探索,最终发现了基于有序频率二叉树编码的想法,并很快证明了这个方法是最有效的。霍夫曼使用自底向上的方法构建二叉树,避免了次优算法香农-范诺编码的最大弊端──自顶向下构建树。

    算法流程:

    假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,则哈夫曼树的构造规则为:

    (1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点);
    (2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;
    (3)从森林中删除选取的两棵树,并将新树加入森林;

    (4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。

    typedef struct TreeNode *HuffmanTree;
    struct TreeNode{
        int Weight;
        HuffmanTree Left, Right;
    }
    
    HuffmanTree Huffman( MinHeap H )
    {   /*  假设H->Size 个权值已经存在H->Elements[]->Weight 里 */
        int i; HuffmanTree T;
        BuildMinHeap(H); /* 将H->Elements[] 按权值调整为最小堆*/
        for (i = 1; i < H->Size; i++) { /* 做H->Size-1 次合并*/
            T = malloc( sizeof( struct TreeNode) ); /* 建立新结点*/
            T->Left = DeleteMin(H);
            /* 从最小堆中删除一个结点 , 作为新T 的左子结点*/
            T->Right = DeleteMin(H);
            /* 从最小堆中删除一个结点 , 作为新T 的右子结点*/
            T->Weight = T->Left->Weight+T->Right->Weight;
            /* 计算新权值*/
            Insert( H, T ); /* 将新T 插入最小堆*/
        }
        T = DeleteMin(H);
        return T;
    }
    

     

    二、哈夫曼编码

    问题:给定一段字符串,如何对字符进行编码 ,可以使得该字符串的编码存储空间最少?

    【例】假设有一段文本,包含58 个字符,并由以下7 个字符构:a ,e ,i, s ,t ,空格(sp),换行(nl);这7个字符出现的次数不同。如何对这7个字符进行编码,使得总编码空间最少?
    【分析】
    (1)用等长ASCII 编码:58  ×8 = 464 位;
    (2)用等长3 位编码:58  ×3 = 174 位;
    (3)不等长编码:出现频率高的字符用的编码短些 ,出现频率低的字符则可以用较长的编码进行表示。

    采用不定长编码编码最本初的问题就是如何避免二义性,在解释一段编码的时候如果有多于一种的解释,显然这种编码就是不可靠的。

    经过证明只要任何字符的编码都不是另一字符编码的前缀,就可以避免二义性。

    显然的是,只要字符出现在叶子结点就不能是另一个编码的前缀码,并且当前的编码问题本质上就是构造哈夫曼树。

  • 相关阅读:
    web服务器-Apache
    nginx优化
    nginx下载限速
    nginx-URL重写
    HDU 5358 First One 求和(序列求和,优化)
    HDU 5360 Hiking 登山 (优先队列,排序)
    HDU 5353 Average 糖果分配(模拟,图)
    UVALive 4128 Steam Roller 蒸汽式压路机(最短路,变形) WA中。。。。。
    HDU 5348 MZL's endless loop 给边定向(欧拉回路,最大流)
    HDU 5344 MZL's xor (水题)
  • 原文地址:https://www.cnblogs.com/hyserendipity/p/8493624.html
Copyright © 2011-2022 走看看