哈夫曼树

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);
}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值