定义:给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。 哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。
在数据通信中,需要将传送的文字转换成二进制的字符串,用0,1码的不同排列来表示字符。例如,需传送的报文为“AFTER DATA EAR ARE ART AREA”, 这里用到的字符集为“A,E,R,T,F,D”,各字母出现的次数为{8,4,5,3,1,1}。现要求为这些字母设计编码。 要区别6个字母,最简单的二进制编码方式是等长编码,固定采用3位二进制,可分别用000、001、010、011、100、101对“A,E,R,T,F,D”进行编码发送, 当对方接收报文时再按照三位一分进行译码。显然编码的长度取决报文中不同字符的个数。若报文中可能出现26个不同字符,则固定编码长度为5。 然而,传送报文时总是希望总长度尽可能短。在实际应用中,各个字符的出现频度或使用次数是不相同的,如A、B、C的使用频率远远高于X、Y、Z,自然会想到设计编码时, 让使用频率高的用短码,使用频率低的用长码,以优化整个报文编码。
哈夫曼静态编码:它对需要编码的数据进行两遍扫描:第一遍统计原数据中各字符出现的频率, 利用得到的频率值创建哈夫曼树,并必须把树的信息保存起来,即把字符0-255(2^8=256)的频率值以2-4BYTES的长度顺序存储起来, (用4Bytes的长度存储频率值,频率值的表示范围为0--2^32-1,这已足够表示大文件中字符出现的频率了)以便解压时创建同样的哈夫曼树进行解压; 第二遍则根据第一遍扫描得到的哈夫曼树进行编码,并把编码后得到的码字存储起来。
哈夫曼动态编码:动态哈夫曼编码使用一棵动态变化的哈夫曼树,对第t+1个字符的编码是根据原始数据中前t个字符得到的哈夫曼树来进行的, 编码和解码使用相同的初始哈夫曼树,每处理完一个字符,编码和解码使用相同的方法修改哈夫曼树,所以没有必要为解码而保存哈夫曼树的信息。 编码和解码一个字符所需的时间与该字符的编码长度成正比,所以动态哈夫曼编码可实时进行。
哈夫曼译码
在通信中,若将字符用哈夫曼编码形式发送出去,对方接收到编码后,将编码还原成字符的过程,称为哈夫曼译码。
1、路径和路径长度
在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。
2、结点的权及带权路径长度
若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
3、树的带权路径长度
树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL。
HuffMan树的构造方法:
假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,则哈夫曼树的构造规则为:
(1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点);
(2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;
(3)从森林中删除选取的两棵树,并将新树加入森林;
创建图示:本次实现huffman树是先根据要要建树的所有关于叶节点的的信息先创建根节点,然后放到vector中,然后重载运算符<或者写一个比较的类这里面实现了静态成员函数的声明预定义,以及如果STL容器内的元素是模板类的指针的声明情况。把vector内的元素按照从小到大进行排序后,每次取最小的两个值,然后根据这两个节点创建一个新的节点,然后在vector中删除这两个最小值的节点,把新值加进来,然后再排一次顺序,再重复操作当容器内只剩一个元素时,这个元素就是这棵huffman树的根节点。二叉树的程序实现:
#include <QCoreApplication>
#include <iostream>
#include <vector>
using namespace std;
//继承自纯虚函数的子类,必须要重写父类的全部纯虚函数,否则编译会报这是一个抽象对象
//HuffMan树因为只有叶节点保存数据,所以叶节点与分支节点分开实现比较好
template<class T>
class HuffManNode
{
public:
virtual int weight()=0;
virtual bool Isleaf() const=0;
virtual void setleft(HuffManNode<T>* Node)=0;
virtual HuffManNode<T>* getleft() const=0;
virtual void setright(HuffManNode<T>* Node)=0;
virtual HuffManNode<T>* getright() const=0;
virtual T getval()const=0;
};
template<class T>
class LeafNode:public HuffManNode<T>
{
private:
int weg;
T val;
public:
LeafNode(int _weight,T _val):weg(_weight),val(_val)
{}
~LeafNode()
{}
virtual int weight()
{
return weg;
}
virtual bool Isleaf() const;
virtual void setleft(HuffManNode<T> *Node)
{}
virtual void setright(HuffManNode<T> *Node)
{}
virtual T getval()const
{
return val;
}
virtual HuffManNode<T>*getleft() const
{
return NULL;
}
virtual HuffManNode<T>*getright() const
{
return NULL;
}
};
template<class T>
bool LeafNode<T>::Isleaf() const
{
return true;
}
template<class T>
class IntenalNode:public HuffManNode<T>
{
private:
HuffManNode<T> *lc;
HuffManNode<T> *rc;
int weg;
public:
IntenalNode(HuffManNode<T>* _lc=NULL,HuffManNode<T>* _rc=NULL):lc(_lc),rc(_rc)
{
weg=lc->weight()+rc->weight();
}
virtual int weight()
{
return weg;
}
virtual bool Isleaf() const
{
return false;
}
virtual void setleft(HuffManNode<T> *Node);
virtual void setright(HuffManNode<T> *Node);
virtual HuffManNode<T>* getleft() const;
virtual HuffManNode<T>* getright() const;
virtual T getval()const
{}
};
template<class T>
void IntenalNode<T>::setleft(HuffManNode<T> *Node)
{
lc=Node;
}
template<class T>
void IntenalNode<T>::setright(HuffManNode<T> *Node)
{
rc=Node;
}
template<class T>
HuffManNode<T>* IntenalNode<T>::getleft() const
{
return lc;
}
template<class T>
HuffManNode<T>* IntenalNode<T>::getright() const
{
return rc;
}
template<class T>
class HuffTree
{
private:
HuffManNode<T> *subroot;
bool operator < (HuffTree<T>* x)
{
return subroot->weight()<x->weight();
}
public:
HuffTree(int _weg,T _val)
{
subroot=new LeafNode<T>(_weg,_val);
}
HuffTree(HuffTree<T> *_lc,HuffTree<T>* _rc)
{
subroot=new IntenalNode<T>(_lc->root(),_rc->root());
}
~HuffTree()
{}
HuffManNode<T>* root()
{
return subroot;
}
int weight()
{
return subroot->weight();
}
};
template<class T>
class HHcompare
{
public:
static bool lt(HuffTree<T>* x,HuffTree<T>* y)
{
return x->weight()<y->weight();
}
static bool gt(HuffTree<T>* x,HuffTree<T>* y)
{
return x->weight()>y->weight();
}
static bool eq(HuffTree<T>* x,HuffTree<T>* y)
{
return x->weight()==y->weight();
}
};
template <class T>
class HuffManTree
{
private:
HuffTree<T>* subroot;
vector<HuffTree<T>* > woods;
vector<HuffTree<T>*> CreateHuffTreate(vector<HuffTree<T>*> &Barry)
{
//获取最前面的两个
sort(Barry.begin(),Barry.end(),HHcompare<T>::lt);//之前先排序
HuffTree<T> *ParNode=new HuffTree<T>(Barry.at(0),Barry.at(1));
class vector<HuffTree<T>*>::iterator it_fir=Barry.begin();
Barry.erase(it_fir);
class vector<HuffTree<T>* >::iterator it_sec=Barry.begin();
Barry.erase(it_sec);
Barry.push_back(ParNode);
return Barry;
}
public:
HuffManTree(HuffTree<T>* _subroot=NULL):subroot(_subroot)
{
woods.empty();
}
~HuffManTree()
{}
T findTpu(string length)
{
HuffManNode<T>*_root=subroot->root();
return findT(_root,length);
}
void insertNode(int _weg,T _val)
{
HuffTree<T>* Node=new HuffTree<T>(_weg,_val);
woods.push_back(Node);
}
void CreateTree()
{
vector<HuffTree<T>*> Barry=woods;
while(Barry.size()>1)
{
CreateHuffTreate(Barry);
}
subroot=Barry.at(0);
}
T findT(HuffManNode<T>*&_root,string length)
{
int size=length.length();
for(int i=0;i<size;i++)
{ if(_root->Isleaf())
{
break;
}
char Num=length.at(i);
if(Num=='1')
{
_root=_root->getleft();
}
else if(Num=='0')
{
_root=_root->getright();
}
}
return _root->getval();
}
};
int main(int argc, char *argv[])
{
HuffManTree<char>* A=new HuffManTree<char>();
A->insertNode(2,'A');
A->insertNode(2,'B');
A->insertNode(3,'C');
A->insertNode(1,'D');
A->insertNode(5,'E');
A->CreateTree();//创建完成,遍历获取编码
char l=A->findTpu("111");
cout<<l<<endl;
cout<<"ds";
return 0;
}