哈夫曼树

来源:互联网 发布:福州seo推广 编辑:程序博客网 时间:2024/05/16 20:32

huffman树,又称最优二叉树,是加权路径长度最短的二叉树
[贪心算法]是指在问题求解时,总是做出当前看起来最好的选择,通俗的说贪心算法不是整体最优的选择,而是局部最优解
使用贪心算法构建Huffman树
这里写图片描述
构建哈夫曼树主要包括两部分:
1:建小堆
2:将加权路径长度最短,构建最短二叉树
一:建小堆:

#pragma once#include<vector>#include<assert.h>using namespace std;template<class T>class Less{public:    bool operator()(const T&a, const T&b)    {        return a < b;    }};template<class T>class Greater{public:    bool operator()(const T&a, const T&b)    {        return a>b;    }};//小堆:任意一个节点是它子树的最大节点template<class T, class Compare = Less<T>>class Heap{public:    Heap()    {}    Heap(T*a, size_t n)    {        _a.reserve(n);//增容(可以直接拷贝数据)        for (size_t i = 0; i < n; i++)        {            _a.push_back(a[i]);        }        //调整成堆        for (int j = (_a.size() - 2) / 2; j >= 0; --j)        {            //向下调整            _AjustDown(j);        }    }    //插入    void Push(const T&x)    {        _a.push_back(x);        //调整成堆        _AjustUp(_a.size() - 1);    }    //删除    void Pop()    {        assert(!_a.empty());        swap(_a[0], _a[_a.size() - 1]);//根节点和最后一个叶子节点交换        _a.pop_back();        _AjustDown(0);    }    const T& Top()    {        return _a[0];    }    size_t Size()    {        return _a.size();    }    bool Empty()    {        return _a.empty();    }protected:    //插入算法,主要影响root路径,向上    void _AjustUp(int child)    {        assert(!_a.empty());        int parent = (child - 1) >> 1;        Compare comFunc;//调用仿函数        while (child>0)        {            //如果孩子节点的值大于父节点的值            if (comFunc(_a[child], _a[parent]))            {                swap(_a[child], _a[parent]);                child = parent;                parent = (child - 1) >> 1;            }            else            {                break;            }        }    }protected:    //向下调整成堆    void _AjustDown(int root)    {        Compare comFuc;        int parent = root;        int child = root * 2 + 1;//左孩子        while (child < _a.size())        {            //选较小的孩子            if (child + 1 < _a.size() && comFuc(_a[child + 1], _a[child]))            {                ++child;            }            //比较父亲与孩子的大小            if (comFuc(_a[child], _a[parent]))            {                swap(_a[child], _a[parent]);                parent = child;                child = parent * 2 + 1;            }            else            {                break;            }        }    }protected:    vector<T>_a;};void TestHeap(){    int a1[] = { 10, 16, 18, 12, 13, 15, 17, 14, 19 };    size_t len = sizeof(a1) / sizeof(a1[0]);    Heap<int, Less<int>>  h1(a1, len);    h1.Top();    /*h1.Push(25);    h1.Pop();*/    while (!h1.Empty())    {        cout << h1.Top() << " ";        h1.Pop();    }    cout << endl;}

二:构建哈夫曼树:
构建哈夫曼树,是所有叶子节点带权路径之和.
建树的思路:
1:将所有节点看成独立的树,且左右子树都为空,
2:选择权值最小的两个节点,生成一个节点作为它们的父节点,父节点的权值等于它们的权值之和
3:将父节点放回重复步骤2直到这个序列中只剩下最后一个节点,此时哈夫曼树就建成了.

#pragma once#include"Heap.h"#include<assert.h>using namespace std;template<class T>struct HuffmanTresNode{    T _w;//权值    HuffmanTresNode<T> *_left;    HuffmanTresNode<T> *_right;    HuffmanTresNode<T> *_parent;    HuffmanTresNode(const T&x = T())        :_w(x)        , _left(NULL)        , _right(NULL)        , _parent(NULL)    {}};template<class T>class HuffmanTree{    typedef HuffmanTresNode<T> Node;public:    //缺省的构造函数    HuffmanTree()        :_root(NULL)    {}    HuffmanTree(T*a, size_t n, const T& invalid = T())//创建huffmanTree    {        assert(a);        //_root = CreatHuffmanTree(a, n, invalid);        //比较权值        struct Compare        {            bool operator()(const Node*l, const Node*r) const            {                return l->_w < r->_w;            }        };        Heap<Node*, Compare> minHeap;//所有元素建小堆        for (size_t i = 0; i < n; ++i)        {            if (a[i] != invalid)            {                minHeap.Push(new Node(a[i]));            }        }        Node*left = NULL;        Node*right = NULL;        while (minHeap.Size()>1)        {            left = minHeap.Top();            minHeap.Pop();            right = minHeap.Top();            minHeap.Pop();            Node*parent = new Node(left->_w + right->_w);            parent->_left = left;            parent->_right = right;            left->_parent = parent;            right->_parent = parent;            minHeap.Push(parent);        }        _root = minHeap.Top();    }    Node* GetHuffmanTree()    {        return _root;    }    ~HuffmanTree()    {        if (_root != NULL)            _Destroy(_root);    }protected:    //释放空间9    void _Destroy(Node*node)    {        if (node == NULL)            return;        _Destroy(node->_left);        _Destroy(node->_right);        delete node;    }protected:    Node* _root;};void TestHuffmanTree(){    int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };    HuffmanTree<int> t(a, 10);}

当然哈夫曼树的一个重要应用就是通过哈夫曼编码来实现文件压缩,关于文件压缩后面我们再来探讨.

原创粉丝点击