先生成哈夫曼树,然后遍历树得到编码。
生成哈夫曼树:
每个字符对应一个权重初始化为一个节点,所有节点按照权重排序,然后选出两个权重最小的两个节点和创建一个新的节点,选出的两个节点作为新创建节点的左右孩子节点,新节点的权值为两个孩子节点的和,然后将新节点放入原来的没选取出的节点中重新排序,重复上述步骤,直到只剩下一个节点,也就是这棵哈夫曼树的根节点了。
最后从根节点开始遍历树,统计从根节点到叶节点的路劲对应的编码就能得到最终结果了。
创建新节点放入剩余节点重新排序这一步骤的时候,如果字符量少可以选择常量时间很低的插入排序,如果数据量大可以利用归并排序的原理,原始节点排序后入队列A,新创建一个队列B,将新创建的节点入队B,因为后创建的节点的权值一定比先创建的节点的权值更大,所以依次入队的话将队列元素将按从小到大排列,之后每次找最小值就只需要较队头元素然后选中较小的一个出队。
代码:
- #include<iostream>
- #include<string>
- #include<algorithm>
- #include<cstring>
- using namespace std;
- #define mem(x) memset(x,0,sizeof(x))
- #define MaxN 30
- //存放剩余没被选出的节点信息
- struct sum{
- double s;
- int num;
- bool operator < (sum x){
- return s<x.s;
- }
- }tree[MaxN+5];
- //存放之后每个新创建节点的孩子节点和自身编号信息
- //也是由这个来存放树
- struct parent{
- int num;
- int left;
- int right;
- }par[2*MaxN+10];
- //存放每个字符信息
- struct data{
- char character;
- double value;
- string code; //存放每个字符的哈夫曼编码
- }A[MaxN+5];
- //遍历树并找到编码
- void FindCode(int num,string code=""){
- if(par[num].left!=0){
- FindCode(par[num].left,code+‘0‘);
- }
- if(par[num].right!=0){
- FindCode(par[num].right,code+‘1‘);
- }
- if((par[num].left+par[num].right)==0){
- A[num].code=code;
- }
- }
- void huffman(int N){
- sum temp;
- mem(A);mem(par);mem(tree);
- for(int i=1;i<=N;i++){
- cin>>A[i].character>>A[i].value;
- tree[i].num=i;
- tree[i].s=A[i].value;
- par[i].num=i;
- }
- //建树
- sort(tree+1,tree+N+1);
- for(int i=1;i<=N-1;i++){
- par[N+i].left=tree[i].num;
- par[N+i].right=tree[i+1].num;
- tree[i+1].s+=tree[i].s;
- tree[i+1].num=N+i;
- int j=i+1;
- temp=tree[i+1];
- //下面是排序 因为数据量小所以选择常量时间低的插入排序
- //如果编码数据多可以利用归并排序的原理进行排序优化时间复杂度
- //也就是合并后的节点值按顺序放入一个新的队列 这个队则会有序 连续两次选出两个队列对头元素中较小的一个
- while(temp.s>tree[j+1].s&&j<N){
- tree[j]=tree[j+1];
- j++;
- }
- tree[j]=temp;
- }
- //下面这个函数用来递归遍历树并记录下正确编码
- FindCode(2*N-1);
- }
- //测试用的主函数
- int main(){
- int num;
- cout<<"how many characters do you want to encoding? please input a number."<<endl;
- cin>>num;
- cout<<"please input all characters and weight value."<<endl;
- huffman(num);
- cout<<"ans:"<<endl;
- for(int i=1;i<=num;i++){
- cout<<A[i].character<<":"<<A[i].code<<endl;
- }
- }