【C++】Huffman树的实现

介绍huffman树之前我们先来看下如下几个基本概念

1、路径和路径长度

路径:我们定义从A节点到B节点所经过的分支序列称为从A节点到B节点的路径。
路径长度:路径中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。
二叉树的路径长度:从二叉树的根节点到二叉树所有节点的路径长度之和,称为二叉树的路径长度。
2、结点的权及带权路径长度
节点的权:若将树中某个结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。
结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
3、树的带权路径长度
树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL
【C++】Huffman树的实现_第1张图片【C++】Huffman树的实现_第2张图片
例如上面两幅图,带权路径长度分别为:
     WPL = 1*2 + 3*2 + 5*2 + 7*2 = 32
     WPL = 1*2 + 3*3 + 5*3 + 7*1 = 33

接下来我们看下Huffman树的原理:

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


接下来看下如何构造Huffman树

我们需要把节点权值较大的树放在离根节点近的地方,这样会使得总的WPL少,所以

1、由给定的n个权值{1,2,3,…,n}构造n棵只有根节点的扩充二叉树森林F= {T1,T2,T3,…,Tn},其中每棵扩充二叉树Ti只有一个带权值wi的根节点,左右孩子均为 空。 

2、重复以下步骤,直到F中只剩下一棵树为止:  

     a、在F中选取两棵根节点的权值最小的扩充二叉树,作为左右子树构造一棵新的二叉树。将新二叉树的根节点的权值为其左右子树上根节点的权值之和。  

     b、在F中删除这两棵二叉树;   

     c、把新的二叉树加入到F中;

即我们主要做以下两个步骤:

1、扩充二叉树森林

【C++】Huffman树的实现_第3张图片

2、两个较小的权值节点相加把新的二叉树放入

【C++】Huffman树的实现_第4张图片

循环以上步骤即构建完成。


由于此huffman树是在堆上建立的,所以此处不再列出堆的实现代码。

下面给出代码:

#include "heap.h"
using namespace std;
template			
struct HuffmanTreeNode
{
	HuffmanTreeNode(const T& weight)
		: _weight(weight)
		, _pLeft(NULL)
		, _pRight(NULL)
		, _pParent(NULL)
	{}

	T _weight;         // Ȩֵ
	HuffmanTreeNode* _pLeft;
	HuffmanTreeNode* _pRight;
	HuffmanTreeNode* _pParent;
};
template
struct ComplareNode
{
	bool operator()(Node* pLeft, Node* pRight)
	{
		return pLeft->_weight_weight;
	}
};

template
class HuffmanTree
{
	typedef HuffmanTreeNode Node;
public:
	HuffmanTree()
		: _pRoot(NULL)
	{}

	HuffmanTree(const T array[], size_t size,)
		:_pRoot(NULL)
	{
		_Create(array,size);
	}
	~HuffmanTree()
	{
		_Destroy(_pRoot);
	}

	const Node* Root()const
	{
		return _pRoot;
	}
private:
	void _Create(const T array[], size_t size)
	{
		Heap*, _complex> hp;
		for (size_t idx = 0; idx < size; ++idx)
		{
			hp.Insert(new Node(array[idx]));
		}
		while (hp.Size() > 1)
		{
			Node* pLeft = hp.Top();
			hp.Remove();
			Node* pRight = hp.Top();
			hp.Remove();

			Node* pParent = new Node(pLeft->whight + pRight->whight);
			pParent->_pLeft = pLeft;
			pParent->_pRight = pRight;

			hp.Insert(pParent);
		}
		_pRoot = hp.Top();
	}
	void _Destroy(Node* & pRoot)
	{
		if (pRoot)
		{
			delete pRoot;
			pRoot = NULL;
		}
	}

protected:
	Node* _pRoot;
};




你可能感兴趣的:(数据结构)