1.从树中一个结点到另外一个结点之间分支构成两个结点之间的路径,是、路径上的分支数目叫做路径长度
2.树的路径长度就是从树根到每一个结点的路径长度之和
3.带权路径长度WPL最小的二叉树称作赫夫曼树
4.若要设计长短不等的编码,则必须是任一字符的编码的前缀,这种编码称为前缀编码
5.一般地,设需要编码的字符集为{d1,d2,...,dn},各个字符在电文中出现的次数或频率集合为{w1,w2,...,wn},以d1,d2,...,dn作为叶子结点,以w1,w2,...,wn作为相应叶子结点的权值来构造一棵赫夫曼树。规定赫夫曼树的左分支代表0,右分支代表1,则从根结点到叶子结点所经过的路径分支组成的0和1的序列便为该结点对应字符的编码,这就是赫夫曼编码
举个例子:
0,1,2,3,4出现的频率分别为5,4,6,2,3
1先把有权值的叶子结点按照从小到大的顺序排成一个有序序列,3 2, 4,3, 1 4, 1 5, 2 6
2.取两个权值最小的作为一个新结点N1,较小的是左孩子,新的孩子的权值是2+3=5,然后再放进队列1 4,1 5,N1 5, 2 6
3.同样二的步骤,知道序列里面只有一个结点
WPL=5*2+4*2+2*3+3*3+6*2=45
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
typedef struct HTNode{
char c;
int freq;
HTNode *lchild, *rchild;
HTNode(char key='\0', unsigned int fr=0, HTNode *l=NULL, HTNode *r=NULL):
c(key),freq(fr),lchild(l),rchild(r){};
}HTNode,*pNode;
//重载优先队列里的比较运算符
struct cmp{
bool operator()(pNode node1, pNode node2){
return node1->freq>node2->freq;
}
};
priority_queue<pNode,vector<pNode>,cmp> pq;
//建Huffman Tree
void HuffmanTree(int n){
pNode left,right;
//从优先队列中找出优先级最小的两个元素,合并,并
//把它加入到优先队列中
while(pq.size()>1){
pNode tmp=new HTNode;
left=pq.top();
pq.pop();
right=pq.top();
pq.pop();
tmp->lchild=left;
tmp->rchild=right;
tmp->freq=left->freq+right->freq;
pq.push(tmp);
}
}
//中序遍历
int B=0;
void PrintCode(pNode t, string str){
if(t==NULL)
return;
//左子树
if(t->lchild){
str+='0';
PrintCode(t->lchild,str);
}
//叶子结点
if(t->lchild==NULL && t->rchild==NULL){
B+=t->freq*str.length();
}
str.erase(str.end()-1); //删除最后一个字符
//右子树
if(t->rchild){
str+='1';
PrintCode(t->rchild,str);
}
}
int main(){
int n;
cin>>n;
char c;
int freq;
string str="";
for(int i=0;i<n;i++){
cin>>c>>freq;
pNode p=new HTNode;
p->c=c;
p->freq=freq;
pq.push(p);
}
HuffmanTree(n);
PrintCode(pq.top(), str);
cout << B << endl;
return 0;
}