题目的链接为: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。按照这个规则,我们可以根据从根节点到叶子节点的路径,得知叶子节点所代表的字母的编码。译码即
逆向思维。
其实对树比较熟悉的话,这道题比较容易就能够做出来。
代码如下:
#include<iostream>
#include<algorithm>
#include<string>
#define MAXNUM 1001
using namespace std;
//哈夫曼树的节点
typedef struct node{
    //树节点的标志 
    char data;      
    //树节点的权重
    int weight;
    //左右孩子
    int lchild;
    int rchild;
    //是否已经被放入树中 
    bool tag; 
}myNode; 
bool compare(myNode mynode1,myNode mynode2)
{
    return mynode1.weight<mynode2.weight; 
}
myNode nodes[100];
char mycode[100];
char ch[]={'A','C','I','M','N','P','T','U'};
int index=-1;
int index1=-1;
//记录每个字母的哈弗曼编码 
string str[8];
myNode recordNode;
bool judge()
{
   int record=0;
   for(int i=0;i<=index;i++)
   {
        if(nodes[i].tag==false)
        {
           record++;
           recordNode=nodes[i];
        } 
   } 
   if(record==0||(record==1&&recordNode.data=='#'))
   {
        return true;
   }
   return false;
}
int findNode()
{
   for(int i=0;i<=index;i++)
   {
        if(nodes[i].tag==false)
        {
             nodes[i].tag=true;
             return i;
        }
   } 
   return -1;
}
//编码
bool code(myNode *root,char ch1)
{
   bool tag=false;
   if(root->data==ch1)
   {
         return true; 
   }
   int arr[2];
   arr[0]=root->lchild;
   arr[1]=root->rchild;
   for(int i=0;i<2;i++)
   {
       if(arr[i]!=-1)
       {   
           tag=code(&nodes[arr[i]],ch1);
           if(tag)
           {
               if(i==0)
               {
                      mycode[++index1]='0'; 
               } 
               else if(i==1)
               {
                      mycode[++index1]='1'; 
               } 
           } 
           if(tag)
           {
                return tag; 
           }
       } 
   }
   return tag;
} 
//创建哈弗曼树 
void createTree()
{
    while(!judge())
    {
         //按照权重由小到大排序 
         sort(nodes,nodes+index+1,compare); 
            
         myNode newNode;
         newNode.data='#';
         newNode.lchild=findNode();
         newNode.rchild=findNode();
         newNode.weight=nodes[newNode.lchild].weight+nodes[newNode.rchild].weight;
         newNode.tag=false;
       
         nodes[++index]=newNode;
    }
}
//输出字母对应的编码 
void outputCode(char cha)
{
    for(int i=0;i<8;i++)
    {
         if(cha==ch[i])
         {
             cout<<str[i];
             break; 
         } 
    }
}
//译码
void decode1(string inputstr)
{
    int kkindex=-1;
    int len=inputstr.length();
    while(kkindex<len)
    {
           bool find=false;
           myNode tempNode=nodes[index];
           char ch;
           while(!find&&kkindex<len)
           {
                  ++kkindex;
                  if(inputstr[kkindex]=='0')
                  {
                       tempNode=nodes[tempNode.lchild]; 
                  }
                  else
                  {
                       tempNode=nodes[tempNode.rchild];
                  }
                  ch=tempNode.data;
                  if(ch!='#')
                  {
                        find=true;
                  }
           }
           if(ch!='#')
           {
              cout<<ch;
           }
    }
} 
void input()
{
    for(int i=0;i<8;i++)
    {
         int data;
         cin>>data;
         
         nodes[++index].data=ch[i];
         nodes[index].weight=data;
         nodes[index].lchild=-1;
         nodes[index].rchild=-1;
         nodes[index].tag=false;
    } 
    
    //构造哈夫曼树 
    createTree();
    
    //recordNode故为树的根 
    for(int i=0;i<8;i++)
    {
         index1=-1;
         code(&(nodes[index]),ch[i]);
         str[i]="";
         for(int j=index1;j>=0;j--)
         {
             str[i]+=mycode[j];
         }
    }
    
    //输出
    for(int i=0;i<8;i++)
    {
         cout<<ch[i]<<": ";
         cout<<str[i]<<endl; 
    } 
    
    //获得输入的字符串
    string inputstr;
    cin>>inputstr;
    for(int i=0;i<inputstr.length();i++)
    {
        outputCode(inputstr[i]); 
    } 
    cout<<endl;
    
    //输出译码结果
    cin>>inputstr; 
    decode1(inputstr);
    cout<<endl;
}
int main()
{
   input();
   
   system("pause");
   return 0; 
}