基本概念
定義從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;
};