Huffman树

来源:互联网 发布:软件设计方案书 编辑:程序博客网 时间:2024/06/05 18:35

哈夫曼树(Huffman):给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。

路径:从A节点到B节点所经过的分支序列成为A节点到B节点的路径
路径长度:从A节点到B节点所经过的分支个数为A到B的路径长度
从根节点到二叉树所有节点的路径长度之和为二叉树的路径长度

哈夫曼树的构造:
假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,则哈夫曼树的构造规则为:
(1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点);
(2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;
(3)从森林中删除选取的两棵树,并将新树加入森林;
(4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。

示例:
int array[]={3,7,12,6}

1、按权值大小排序,int array[]={3,6,7,12}
2、取权值最小的两个节点,作为新树的左右节点,将左右子树的权值相加作为新的根节点的权值
这里写图片描述
3、将旧的节点删除,并将新的根节点放入队列
4、重复2、3,直到队列中只剩一个节点
这里写图片描述WPL=3*3+3*6=2*7+1*12=53

代码实现如下:

1、按权值排列时与小堆相似,所以调用堆的代码

#include<iostream>using namespace std;#include<vector>#include<assert.h>template<class T> //Huffman树是按小堆排列的struct Less{   bool operator()(const T& left,const T& right)   {      return left<right;   }};template<class T>struct Greater{   bool operator()(const T& left,const T& right)   {      return left>right;   }};template<class T,class compare=Less<T>>class Heap{public:    Heap()    {}    Heap(const T array[],size_t size)    {       _heap.resize(size);       for(size_t i=0; i<size; ++i)           _heap[i]=array[i];       int root=(_heap.size()-2)>>1;       for(root=root;root>=0; --root)           _AdjustDown(root);    }protected:    void _AdjustDown(size_t parent)    {       size_t size=_heap.size();       size_t child=parent*2+1;       while(child<size)       {           compare com;          if( child+1<size && com(_heap[child+1],_heap[child]))              child+=1;          if(com(_heap[child],_heap[parent]))          {              std::swap(_heap[parent],_heap[child]);              parent=child;              child=parent*2+1;          }          else               return;       }    }    void _AdjustUp()    {        size_t child=_heap.size()-1;        size_t parent=(child-1)>>1;        while(child != 0)        {           if(compare()(_heap[child],_heap[parent]))           {               std::swap(_heap[child],_heap[parent]);               child=parent;               parent=(child-1)>>1;           }           else               return;        }    }public:    void Insert(const T& data)    {       _heap.push_back(data);       if(_heap.size()>1)           _AdjustUp();    }    void Remove()    {       assert(!Empty());       std::swap(_heap[0],_heap[_heap.size()-1]);       _heap.pop_back();       if(_heap.size()>1)           _AdjustDown(0);    }    size_t Size()const    {        return _heap.size();    }    bool Empty()const    {        return 0 ==_heap.size();    }    const T& Top()const    {        return _heap[0];    }private:    vector<T> _heap;};

2、创建Huffman树

#include "heap.cpp"template<class T>struct HuffmanTreeNode //创建节点{   HuffmanTreeNode(const T& weight)       :_weight(weight)       ,_pLeft(NULL)       ,_pRight(NULL)       ,_pParent(NULL)   {}   T _weight;   HuffmanTreeNode<T>* _pLeft;   HuffmanTreeNode<T>* _pRight;   HuffmanTreeNode<T>* _pParent;};template<class T>class HuffmanTree{   typedef HuffmanTreeNode<T> Node;public:   HuffmanTree()       :_pRoot(NULL)   {}   HuffmanTree(const T array[],size_t size,const T& invalid)   {      _Create(array,size,invalid);   }   ~HuffmanTree()   {      _Destroy(_pRoot);   }private:    void _Create(const T array[],size_t size,const T& invalid) //创建Huffman树    {       struct Compare       {          bool operator()(const Node* pLeft,const Node* pRight)          {             return pLeft->_weight<pRight->_weight;          }       };       Heap<Node*,Compare> hp;       for(size_t i=0;i<size;++i)       {          if(array[i] != invalid)              hp.Insert(new Node(array[i]));       }          while(hp.Size()>1)          {             Node* pLeft=hp.Top();             hp.Remove();             Node* pRight=hp.Top();             hp.Remove();  //取权值最小的两个节点,并删除节点             Node* pParent=new Node(pLeft->_weight+pRight->_weight);  //构造新的根节点             pParent->_pLeft=pLeft;             pParent->_pRight=pRight;             pLeft->_pParent=pParent;             pRight->_pParent=pParent; //将节点连接起来             hp.Insert(pParent); //将新的根节点放入队列          }          _pRoot=hp.Top();   }       const Node* pRoot()const       {          return _pRoot;       }       void _Destroy(Node*& pRoot)       {          if(pRoot)          {             _Destroy(pRoot->_pLeft);             _Destroy(pRoot->_pRight);             delete pRoot;             pRoot=NULL;          }       }private:    Node* _pRoot;};

带权路径长度(WPL)=节点的权值*根节点到该节点的长度
一棵树的带权路径长度=所有节点的带权路径长度之和

0 0
原创粉丝点击