哈弗曼编码与译码

题目的链接为: http://acm.njupt.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=1022
题目的描述为:
哈夫曼编码与译码
时间限制(普通/Java):1000MS/3000MS          运行内存限制:65536KByte
总提交:343            测试通过:123

描述

已知电文包括的字符集为{A,C,I,M,N,P,T,U},输入对应权值,对字符集合进行哈夫曼编码,完成电文的哈夫曼编码与译码工作。

输入


共三行:
第一行为对应字符集{A,C,I,M,N,P,T,U}的权值
第二行为一段字符串表示的电文(长度不超过1000);
第三行为一段电文的哈夫曼编码。

输出


共十行:

前八行为各字符的编码;

第九行是与第二行输入对应的哈夫曼编码;

第十行是与第三行输入对应的电文。


样例输入

1 2 3 4 5 6 7 8
NUPTICPCACM
1111011111100

样例输出

A: 11110
C: 11111
I: 1110
M: 100
N: 101
P: 110
T: 00
U: 01
1010111000111011111110111111111011111100
ACM

哈弗曼编码,是一种很常用的压缩数据的方式。它将频率出现得高的用短编码,频率出现得低的字母用长编码。对哈夫曼编码的理解,就是对压缩的理解。
如对于A,C,I,M,N,P,T,U
他们出现的频率为1,2,3,4,5,6,7,8
首先将他们全都变为单个的树节点,然后将权重小的组成树,即选择1,2组成树,这个树的权重为3,左子树为1,右子树为2,将新的树放入集合。
3(1,2),3,4,5,6,7,8
最小的是权重为3的两颗树,将其合并为新的树,并放入集合:
4,5,6,6(3(1,2),3),7,8
依次类推,就可以建立一颗哈弗曼树。哈夫曼树从节点到左子树根节点为0,到右子树根节点为1。按照这个规则,我们可以根据从根节点到叶子节点的路径,得知叶子节点所代表的字母的编码。译码即逆向思维。
其实对树比较熟悉的话,这道题比较容易就能够做出来。
代码如下:
C++代码 复制代码
  1. #include<iostream>   
  2. #include<algorithm>   
  3. #include<string>   
  4. #define MAXNUM 1001   
  5. using namespace std;   
  6. //哈夫曼树的节点   
  7. typedef struct node{   
  8.   
  9.     //树节点的标志    
  10.     char data;         
  11.     //树节点的权重   
  12.     int weight;   
  13.     //左右孩子   
  14.     int lchild;   
  15.     int rchild;   
  16.     //是否已经被放入树中    
  17.     bool tag;    
  18. }myNode;    
  19. bool compare(myNode mynode1,myNode mynode2)   
  20. {   
  21.     return mynode1.weight<mynode2.weight;    
  22. }   
  23. myNode nodes[100];   
  24. char mycode[100];   
  25. char ch[]={'A','C','I','M','N','P','T','U'};   
  26. int index=-1;   
  27. int index1=-1;   
  28. //记录每个字母的哈弗曼编码    
  29. string str[8];   
  30. myNode recordNode;   
  31. bool judge()   
  32. {   
  33.    int record=0;   
  34.    for(int i=0;i<=index;i++)   
  35.    {   
  36.         if(nodes[i].tag==false)   
  37.         {   
  38.            record++;   
  39.            recordNode=nodes[i];   
  40.         }    
  41.    }    
  42.    if(record==0||(record==1&&recordNode.data=='#'))   
  43.    {   
  44.         return true;   
  45.    }   
  46.    return false;   
  47. }   
  48. int findNode()   
  49. {   
  50.    for(int i=0;i<=index;i++)   
  51.    {   
  52.         if(nodes[i].tag==false)   
  53.         {   
  54.              nodes[i].tag=true;   
  55.              return i;   
  56.         }   
  57.    }    
  58.    return -1;   
  59. }   
  60. //编码   
  61. bool code(myNode *root,char ch1)   
  62. {   
  63.    bool tag=false;   
  64.    if(root->data==ch1)   
  65.    {   
  66.          return true;    
  67.    }   
  68.    int arr[2];   
  69.    arr[0]=root->lchild;   
  70.    arr[1]=root->rchild;   
  71.    for(int i=0;i<2;i++)   
  72.    {   
  73.        if(arr[i]!=-1)   
  74.        {      
  75.            tag=code(&nodes[arr[i]],ch1);   
  76.            if(tag)   
  77.            {   
  78.                if(i==0)   
  79.                {   
  80.                       mycode[++index1]='0';    
  81.                }    
  82.                else if(i==1)   
  83.                {   
  84.                       mycode[++index1]='1';    
  85.                }    
  86.            }    
  87.            if(tag)   
  88.            {   
  89.                 return tag;    
  90.            }   
  91.        }    
  92.    }   
  93.   
  94.    return tag;   
  95. }    
  96. //创建哈弗曼树    
  97. void createTree()   
  98. {   
  99.     while(!judge())   
  100.     {   
  101.          //按照权重由小到大排序    
  102.          sort(nodes,nodes+index+1,compare);    
  103.                
  104.          myNode newNode;   
  105.          newNode.data='#';   
  106.          newNode.lchild=findNode();   
  107.          newNode.rchild=findNode();   
  108.          newNode.weight=nodes[newNode.lchild].weight+nodes[newNode.rchild].weight;   
  109.          newNode.tag=false;   
  110.           
  111.          nodes[++index]=newNode;   
  112.     }   
  113. }   
  114. //输出字母对应的编码    
  115. void outputCode(char cha)   
  116. {   
  117.     for(int i=0;i<8;i++)   
  118.     {   
  119.          if(cha==ch[i])   
  120.          {   
  121.              cout<<str[i];   
  122.              break;    
  123.          }    
  124.     }   
  125. }   
  126. //译码   
  127. void decode1(string inputstr)   
  128. {   
  129.     int kkindex=-1;   
  130.     int len=inputstr.length();   
  131.     while(kkindex<len)   
  132.     {   
  133.            bool find=false;   
  134.            myNode tempNode=nodes[index];   
  135.            char ch;   
  136.            while(!find&&kkindex<len)   
  137.            {   
  138.                   ++kkindex;   
  139.                   if(inputstr[kkindex]=='0')   
  140.                   {   
  141.                        tempNode=nodes[tempNode.lchild];    
  142.                   }   
  143.                   else  
  144.                   {   
  145.                        tempNode=nodes[tempNode.rchild];   
  146.                   }   
  147.                   ch=tempNode.data;   
  148.                   if(ch!='#')   
  149.                   {   
  150.                         find=true;   
  151.                   }   
  152.            }   
  153.            if(ch!='#')   
  154.            {   
  155.               cout<<ch;   
  156.            }   
  157.     }   
  158. }    
  159. void input()   
  160. {   
  161.     for(int i=0;i<8;i++)   
  162.     {   
  163.          int data;   
  164.          cin>>data;   
  165.             
  166.          nodes[++index].data=ch[i];   
  167.          nodes[index].weight=data;   
  168.          nodes[index].lchild=-1;   
  169.          nodes[index].rchild=-1;   
  170.          nodes[index].tag=false;   
  171.     }    
  172.        
  173.     //构造哈夫曼树    
  174.     createTree();   
  175.        
  176.     //recordNode故为树的根    
  177.     for(int i=0;i<8;i++)   
  178.     {   
  179.          index1=-1;   
  180.          code(&(nodes[index]),ch[i]);   
  181.          str[i]="";   
  182.          for(int j=index1;j>=0;j--)   
  183.          {   
  184.              str[i]+=mycode[j];   
  185.          }   
  186.     }   
  187.        
  188.     //输出   
  189.     for(int i=0;i<8;i++)   
  190.     {   
  191.          cout<<ch[i]<<": ";   
  192.          cout<<str[i]<<endl;    
  193.     }    
  194.        
  195.     //获得输入的字符串   
  196.     string inputstr;   
  197.     cin>>inputstr;   
  198.     for(int i=0;i<inputstr.length();i++)   
  199.     {   
  200.         outputCode(inputstr[i]);    
  201.     }    
  202.     cout<<endl;   
  203.        
  204.     //输出译码结果   
  205.     cin>>inputstr;    
  206.     decode1(inputstr);   
  207.     cout<<endl;   
  208. }   
  209. int main()   
  210. {   
  211.    input();   
  212.       
  213.    system("pause");   
  214.    return 0;    
  215. }  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值