哈夫曼(Huffman)树及其应用

Huffman树又称最优树,是一类带权路径长度最短的树,带权路径长度为从该节点到树根之间的路径长度与节点上权值的成积。

那么如何构建一个Huffman树呢?就需要Huffman算法

1、利用给定的n个权值构成有n个二叉树的集合F,每个二叉树就只有一个带权值的根节点,其左右子树都为空。

2、选取两课根节点权值最小的树作为左右子树,且重置新的二叉树的根节点的权值为左右子树权值之和。

3、在集合F中删掉这两课子树,并将新得到的二叉树加入到F中去。

4、重复2、3操作直至F中只剩下一棵子树。

如下图:Huffman的构造过程(其中红色数字表示的是节点的权值)

Huffman存储:Huffman树中没有度为一的结点,一棵有n个叶子结点的Huffman树共有2n-1个结点,可以存储在一个大小为2n-1的一维数组中。

                    编码走一条从根路径出发到叶子节点的路径;译码走一条从叶子节点出发到根的路径,对于每个结点而言即需要知道其父亲结点又要知道其左右孩子结点。

Huffman树建立主要代码实现:

:以下代码是借助自己写的堆实现的,也可以用vector容器

void CreateTree(const T* a, size_t size, const T& invalid)
    {
        assert(a);
        Heap<Node*, NodeCompare<T>> minHeap;//一个小堆的结构
        for (size_t i = 0; i < size; ++i)
        {
            if (a[i] != invalid)
            {
                //将a[i]构建成节点,插入堆
                Node* node = new Node(a[i]);
                minHeap.Push(node);
            }
        }
        while (minHeap.Size()>1)
        {//得到权值最小的两个元素作为左右子树
            Node* left = minHeap.Top();
            minHeap.Pop();
            Node* right = minHeap.Top();
            minHeap.Pop();
            //利用左右子树的权值之和构造出结点
            Node* parent = new Node(left->_weight + right->_weight);
//进行链接 parent
->_left = left; parent->_right = right; left->_parent = parent; right->_parent = parent; minHeap.Push(parent); } _root = minHeap.Top(); }

 Huffman编码:约定左分支表示字符'0',右分支表示字符'1',则可以从根节点到叶子节点的路径上分支字符组成的字符串作为该叶子结点字符的编码, 以下写了2 种方法实现记录Huffman编码

    1.递归

   

void _GenerateHuffmanCode(HuffmanTreeNode<FileInfo>* root)//从根节点出发递归生成HuffmanTree编码
    {
        if (root == NULL)
        {
            return;
        }
        _GenerateHuffmanCode(root->_left);
        _GenerateHuffmanCode(root->_right);
        if (root->_left == NULL && root->_right == NULL)//节点为叶子节点
        {
            HuffmanTreeNode<FileInfo>* cur = root;
            HuffmanTreeNode<FileInfo>* parent = cur->_parent;
            string& code = _infos[cur->_weight._ch]._code;//FileInFo即为weight,.ch指的是字符是什么._code表示编码
            while (parent)
            {
                if (parent->_left == cur)
                {
                    code += '0';
                }
                else
                {
                    code += '1';
                }
                    cur = parent;
                parent = cur->_parent;
            }
            reverse(code.begin(), code.end());
        }
    }

文件压缩:

              1、打开文件统计字符次数,利用字符次数建立Huffman树。

              2、根据Huffman树遍历出Huffman编码。

              3、将每一个字符的编码写入压缩文件。

              4、将字符总数及每个按文件中出现顺序字符的次数写入配置文件

文件解压缩:

               1、读配置文件,将字符写入解压缩文件。

原文地址:https://www.cnblogs.com/Blog-day/p/My_Blog_Days_19.html