huffman树

概念 给定 n 个权值作为 n 个页子节点,构造一颗二叉树,若带权路径长度达到最小,称这样的二叉树为哈夫曼树。huffman树是带权路径长度最短的树,权值较大的节点离根节点较近。

构造 huffman 树
1、由给定的n个权值{w1,w2,w3,…,wn}构造n棵只有根节点的二叉树森林F=
{T1,T2,T3,…,Tn},每棵二叉树Ti只有一个带权值wi的根节点,左右孩子均为空。
2、重复以下步骤,直到F中只剩下一棵树为止:
a、在F中选取两棵根节点的权值最小的二叉树,作为左右子树构造一棵新的二
叉树。新二叉树的根节点的权值为其左右子树上根节点的权值之和。
b、在F中删除这两棵二叉树;
c、把新的二叉树加入到F中

因为在这里每次要取出两棵权值最小的二叉树,合并之后又需要再插入会原森林中,所以我们可以借助堆排序的特点,对二叉树森林的内容进行排序。
实现:

template<class 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 i = (_a.size() - 2) / 2; i >= 0; --i)
        {
            AdjustDown(i);
        }
    }
    T& Top() {
        assert(!_a.empty());
        return _a[0];
    }
    void AdjustDown(int root) {//向下 调整
        int parent = root;
        size_t child = parent * 2 + 1;
        while (child < _a.size())//没有页子节点时
        {
            if (child + 1 < _a.size() && _a[child + 1] < _a[child]) //如果右孩子大于左孩子
                child++;    //偏移到右孩子
            if (_a[child] < _a[parent])   //如果左孩子大于父节点
            {
                swap(_a[child], _a[parent]);  //将较大值给父节点
                parent = child;
                child = parent * 2 + 1;
            }
            else  //
                break;
        }
    }
    void AdjustUp(int root) {  // 向上调整
        int parent = (root - 1) / 2;
        while (root > 0) {  //到达根节点
            if (_a[root] < _a[parent]) {
                swap(_a[root], _a[parent]);
                root = parent;
                parent = (root - 1) / 2;
            }
            else    // 小于根节点 则不需要再调整
                break;
        }
    }
    void Push( T& h) {  //插入  向上计算大小并交换   直到是根或者小于根节点值停止
        _a.push_back(h);
        AdjustUp(_a.size() - 1);
    }
    void Pop() {   //  删除根节点 
        assert(!_a.empty());
        //将根节点与最后一个节点交换
        swap(_a[0], _a[_a.size() - 1]);
        _a.pop_back();
        AdjustDown(0);
    }
public:
    //堆排序
    void HeapSort() //堆排序
    {       // 1 2 3 4 5 6
        int num = _a.size();
        int i = num - 1;
        for (; i > 0; i--) {
            swap(_a[0], _a[i]);
            HeapSortAdjust(i);
        }
    }
private:
    void HeapSortAdjust(int size){
        int parent = 0;
        size_t child = parent * 2 + 1;
        while (child < size)//没有页子节点时
        {
            if (child + 1 < size && _a[child + 1] > _a[child]) //如果右孩子大于左孩子
                child++;    //偏移到右孩子
            if (_a[child] > _a[parent])   //如果左孩子大于父节点
            {
                swap(_a[child], _a[parent]);  //将较大值给父节点
                parent = child;
                child = parent * 2 + 1;
            }
            else  //父节点大于等于
                break;
        }
    }
public:
    vector<T> _a;
};

#if 1
template<class T>
class HuffmanTreeNode
{
public:
    HuffmanTreeNode()  //构造
        :_weight(0)
        ,leftchild(NULL)
        ,rightchild(NULL)
    {}
    HuffmanTreeNode(int weight)
        :_weight(weight)
        , leftchild(NULL)
        , rightchild(NULL)
    {}
    bool operator<(HuffmanTreeNode &htnode)
    {
        return this->_weight < htnode._weight;

    }
    bool operator>(HuffmanTreeNode &htnode)
    {
        return this->_weight > htnode->_weight;
    }
    ~HuffmanTreeNode()
    {}
    int _weight; //权值
    HuffmanTreeNode<T> * leftchild;
    HuffmanTreeNode<T> * rightchild;
};
template<class T>
class HuffmanTree
{
public:
    typedef HuffmanTreeNode<T> Node;
    HuffmanTree(T *arr,int size)
    {
        Heap<Node> hp;
        int i = 0;
        Node* h; // 先用堆去维护
        for (i = 0; i < size; i++) {
            h = new Node(arr[i]);
            hp.Push(*h); //1 3 5 7
        }
        Node* h1;
        Node* h2;
        while(hp._a.size()>1)
        {
            h1 = new Node(hp._a[0]);
            hp.Pop();
            h2 = new Node(hp._a[0]);
            hp.Pop();
            h = new Node(h1->_weight+h2->_weight);
            if (h1->_weight > h2->_weight) {
                h->leftchild = h2;
                h->rightchild = h1;
            }
            else
            {
                h->leftchild = h1;
                h->rightchild = h2;
            }
            hp.Push(*h);
        }
        _root = new Node(hp.Top());
    }
    ~HuffmanTree()
    {}
private:

    HuffmanTreeNode<T>* _root;

};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值