哈夫曼树原理和实现

哈夫曼树:
n个带权值节点构造的二叉树中带权路径长度最短的二叉树,并且n个节点都是叶子节点,只有叶子节点才是有效的节点,又称为最优二叉树;
带权路径长度(WPL):
树中所有叶子节点到根节点的路径长度和该叶子节点权值乘积之和。
WPL=W1*L1+W2*L2+…+Wi*Li;
Wi:表示第i个叶子节点的权值;
Li:表示第i个叶子节点到根节点的路径长度。

构造哈夫曼树:

1.将给定的n个权值,每个权值可以看作是一颗只有根节点的树,组成一个集合;
2.在集合中选出根节点权值最小的两棵树,将其权值相加得到新的权值,构造新的树;
3.将刚被选中的两颗树从集合中删去,并将新权值构造的树加入集合中;
4.重复上述两步,直至集合中只剩一棵树。

这里写图片描述

代码实现哈夫曼树:

#include"Heap.h"
using namespace std;

//哈夫曼树节点类
template<class T>
struct HuffmanTreeNode
{
    //构造函数
    HuffmanTreeNode(const T& x)
    :_w(x)
    , _left(NULL)
    , _right(NULL)
    {}

    T _w;
    HuffmanTreeNode<T> *_left;
    HuffmanTreeNode<T> *_right;
};

//构建哈夫曼树
template<class T>
class HuffmanTree
{
    typedef HuffmanTreeNode<T> Node;
public:
    HuffmanTree()
        :_root(NULL)
    {}
    HuffmanTree(T* arr, size_t size, const T& invalid)
    {
        //内部类(重载Heap仿函数)
        struct Compare
        {
            bool operator()(Node* l, Node* r)const
            {
                return l->_w < r->_w;
            }
        };

        //建小堆每次选出数组中两个最小的数进行构造哈夫曼树
        //Heap里面传节点为了能将以前和现在的节点连接在一起
        Heap<Node*, Compare > Min_Heap;
        for (int i = 0; i < (int)size; ++i)
        {
            if (arr[i] != invalid)
            {
                Min_Heap.Push(new Node(arr[i]));
            }
        }
        while (Min_Heap.Size()>1)
        {
            Node* left = Min_Heap.Top();
            Min_Heap.Pop();//每一次执行Pop操作之后,堆就被重新再调整一次,再选出次大的数
            Node* right = Min_Heap.Top();
            Min_Heap.Pop();

            //将最小的两个数相加的结果存放在一个parent节点中
            Node* parent = new Node(left->_w + right->_w);
            //将parent节点和left,right节点链起来,再入堆选出最小的两个数
            parent->_left = left;
            parent->_right = right;
            Min_Heap.Push(parent);
        }
        _root = Min_Heap.Top();
    }

    Node* Get_Top()
    {
        return _root;
    }

    //析构函数
    ~HuffmanTree()
    {
        if (_root)
        {
            Destroy(_root);
        }
    }
    void Destroy(Node* root)
    {
        if (root == NULL)
        {
            return;
        }
        Destroy(root->_left);
        Destroy(root->_right);
        delete root;
    }

private:
    Node* _root;
};
void Test()
{
    int a[] = { 1, 5, 2, 4, 6, 7, 0, 3, 8, 9 };

    HuffmanTree<int> h(a, sizeof(a) / sizeof(a[0]), 0);

}

哈夫曼树的特性:

1.哈夫曼树没有度为1的节点;
2.权值越小离根节点越远,权值越大离根节点越近;
3.哈夫曼树左右子树交换,不会影响带权路径长度;
4.叶子节点才是有效的节点,非叶子节点都是用叶子节点构造出来的;
5.一颗有n个叶子节点的哈夫曼树,总节点为2*n-1。

哈夫曼树的应用:
给定一段字符串,如何对字符串进行编码,使得该字符串编码存储空间最小?
——哈夫曼编码。
这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_39295755/article/details/80154653