概念 给定 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;
};