基本概念
定义从A结点到B结点所经过的分支序列为从A结点到B结点的路径;
定义从A结点到B结点所进过的分支个数为从A结点到B结点的路径长度;
从二叉树的根结点到二叉树中所有结点的路径长度纸盒为该二叉树的路径长度;
Huffman树:带权值路径长度最小的扩充二叉树应是权值大的外界点举例根结点最近的扩充二叉树,该树即为Huffman树;
构建二叉树
Huffman树的构造算法(哈夫曼算法):
(1):根据给定的n个权值{W1,W2,···,Wn}构成n颗二叉树的集合F={T1,T2,···,Tn},其中没课文茶树Ti中只有一个带权WieWi的根结点,其左右子树均为空。
(2):在F中选取两颗根结点的权值最小的数作为左右子树构造一颗新的二叉树,且置新的二叉树的根结点的权值为其左右子树上根结点的权值之和。
(3):在F中删除这两棵树,同时将新得到的二叉树加入F中。
(4):重复(2)(3),直到F中只含有一棵树位置。这可便是HuffmanTree;
因此:我们要将所提供的所有元素放入一个序列中来为Huffman树提供存放的地方,因为每次都要找两个最小的结点,所以,我们能想到的就是创建一个小堆,来存放所有的结点;其实堆中存放的每个结点都是一棵树,所以里面就是一片森林;
如果对堆有不理解的可以看看我的上一篇博文堆的创建,插入,删除;
创建树的代码:
Node* _CreatTree(const T array[], size_t size, T invalid)
{
Heap<Node*, Last<Node*>> _ht;
for (size_t idx = 0; idx < size; ++idx)
{
if (array[idx] != invalid)
{
_ht.Push(new Node(array[idx])); //创建每个结点放在Heap中
}
}
while (_ht.Size() > 1) //直到只有一个结点的时候就是最终的huffman树
{
Node* left = _ht.Top();
_ht.Pop();
Node* right = _ht.Top();
_ht.Pop();
Node* NewParent = new Node(left->_weight + right->_weight);
NewParent->_pLeft = left;
left->_pParent = NewParent;
NewParent->_pRight = right;
right->_pParent = NewParent;
_ht.Push(NewParent);
}
return _ht.Top();
}
Huffman编码
在数据通信中经常需要将传输的文字转换成二进制字符0和1的二进制串,称该过程为编码;
在编码过程中,任意一个字符的编码都不是另一个字符的编码的前缀,这种编码称为前缀编码;
设计电文总长最短的二进制前缀编码即为以n种字符出现的频率做权,设计一颗哈夫曼树的问题,由此得到的二进制前缀编码便称为哈夫曼编码;
在每个字符的下面就是他们的Huffman编码;
下面是从堆开始直到构建好Huffman树的完整代码。因为在下篇博文文件压缩中要用到这些代码
#include<vector>
#include<iostream>
#include<assert.h>
using namespace std;
//创建小堆
template<class T>
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>
struct Last
{
bool operator()(const T& left, const T& right)
{
return left->_weight < right->_weight;
}
};
template<class T, class Compare = Less<T>>
class Heap
{
public:
Heap()
: _hp(NULL)
{}
Heap(const T array[], size_t size)
{
_hp.resize(size);
for (size_t idx = 0; idx < size; idx++)
{
_hp[idx] = array[idx];
}
int parent = (size - 2) >> 1;
for (; parent >= 0; --parent)
{
_AdjustDown(parent);
}
}
bool Empty()
{
return _hp.empty();
}
size_t Size()
{
return _hp.size();
}
T& Top()
{
assert(!_hp.empty());
return _hp[0];
}
void Push(const T& data)
{
_hp.push_back(data);
_AdjustUp();
}
void Pop()
{
assert(!_hp.empty());
std::swap(_hp[0], _hp[_hp.size() - 1]);
_hp.pop_back();
_AdjustDown(0);
}
private:
void _AdjustDown(size_t parent)
{
size_t child = parent * 2 + 1;
while (child < _hp.size())
{
Compare cm;
if (child + 1 < _hp.size() && cm(_hp[child + 1], _hp[child]))
{
child += 1;
}
if (cm(_hp[child], _hp[parent]))
{
std::swap(_hp[child], _hp[parent]);
parent = child;
child = parent * 2 + 1;
}
else
return;
}
}
void _AdjustUp()
{
size_t child = _hp.size() - 1;
while (child != 0)
{
size_t parent = (child - 1) >> 1;
Compare cm;
if (cm(_hp[child], _hp[parent]))
{
std::swap(_hp[child], _hp[parent]);
child = parent;
}
else
return;
}
}
private:
vector<T> _hp;
};
//HuffmanTree
template<class T>
struct HuffmanTreeNode
{
HuffmanTreeNode(const T& weight, const T data = T())
: _weight(weight)
, _pParent(NULL)
, _pLeft(NULL)
, _pRight(NULL)
{}
T _data;
T _weight;
HuffmanTreeNode<T>* _pParent;
HuffmanTreeNode<T>* _pLeft;
HuffmanTreeNode<T>* _pRight;
};
template<class T>
class HuffmanTree
{
typedef HuffmanTreeNode<T> Node;
public:
HuffmanTree()
: _pRoot(NULL)
{}
HuffmanTree(const T array[], size_t size, T invalid)
{
_pRoot = _CreatTree(array, size, invalid);
}
Node* GreatRoot()
{
return _pRoot;
}
private:
Node* _CreatTree(const T array[], size_t size, T invalid)
{
Heap<Node*, Last<Node*>> _ht;
for (size_t idx = 0; idx < size; ++idx)
{
if (array[idx] != invalid)
{
_ht.Push(new Node(array[idx])); //创建每个结点放在Heap中
}
}
while (_ht.Size() > 1) //直到只有一个结点的时候就是最终的huffman树
{
Node* left = _ht.Top();
_ht.Pop();
Node* right = _ht.Top();
_ht.Pop();
Node* NewParent = new Node(left->_weight + right->_weight);
NewParent->_pLeft = left;
left->_pParent = NewParent;
NewParent->_pRight = right;
right->_pParent = NewParent;
_ht.Push(NewParent);
}
return _ht.Top();
}
private:
Node* _pRoot;
};