一、基本概念
1、哈夫曼树(Huffman tree),又名最优树,指给定n个权值作为n的叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。
2、路径与路径长度
在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。
若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。
3、结点的权与带权路径长度
带权结点:位于一棵树的叶子结点处。
若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。
结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
4、树的带权路径长度
树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL。
二、Huffman树的构造
1、创建以权值为根的二叉树森林
2、创建Huffman树—–>小堆
(1)取权值最小的树,作为left,并且从堆中将此元素删除
(2)再一次取权值最小的树,作为right,并且从堆中将此元素删除
(3)以left与right的权值创建新的结点parent,并让其parent的left指向left,parent的 right指向right,成功指向完成之后,并将其加入到二叉树森林中。
注意:需要判断堆中元素的个数,且不能利用堆中的比较器,堆中的比较器是比较的是地址,而在Huffman树中,需要比较的是树中权值的大小,因此,需要重新定义比较器,从而比较每个结点的权值。
构造树的代码如下所示:
过程:
void _CreatHuffmanTree(W*array, size_t size, const W& invalid)
{
//定义比较器,此处使用的原因是:在此要比较的是权值的大小
struct Less
{
bool operator()(pNode left, pNode right)
{
return left->_weight < right->_weight;
}
};
priority_queue<pNode, vector<pNode>, Less> hp;
//将所有元素先放入到堆中
for (size_t i = 0; i < size; ++i)
{
if (array[i] != invalid)
hp.push(new HuffmanTreeNode<W>(array[i]));
}
//堆中没有元素(空堆)
if (hp.empty())
_pRoot = NULL;
//利用堆创建Huffman树
while ((int)hp.size()>1)
{
pNode pLeft = hp.top();
hp.pop();
pNode pRight = hp.top();
hp.pop();
pNode parent = new HuffmanTreeNode<W>(pLeft->_weight + pRight->_weight);
parent->_pLeft = pLeft;
parent->_pRight = pRight;
hp.push(parent);
}
_pRoot = hp.top();
}
三、树的析构函数
因为在树中,有对结点的申请,因此需要析构函数,从而确保内存安全。具体析构过程如下所示:
{
//后序遍历
pNode pCur = pRoot;
if (pCur)
{
Destory(pCur->_pLeft);
Destory(pCur->_pRight);
delete pCur;
pCur = NULL;
}
}
四、整体代码实现
首先利用库中的优先级队列,则实现过程如下:
库中
template < class T, class Container = vector<T>,
class Compare = less<typename Container::value_type> > class<