C++用数据结构-’树‘进行二元哈夫曼的编译码

学过信源编译码的人都知道,哈夫曼编码是不等长编码,且编码效率很高,在此,笔者利用c++语言实现哈夫曼的编译码与读者进行分享。

笔者实现哈夫曼编译码的代码逻辑如下图所示:


具体的代码实现如下:

#include <iostream>

#include <iomanip>

using namespace std;

struct HNode

{

         intweight;   //结点权值

           int parent;   //双亲指针

         intLChild;       //左孩子指针

         intRChild ;      //右孩子指针

};   

struct HCode

 {

         chardata;

         charcode[100];

 };

 

class Huffman

{

private:

         HNode* HTree;                   //Huffman树 

         HCode*HCodeTable;               //Huffman编码表

         charstr[1024];                  //输入的原始字符串

         charleaf[256];                  //叶子节点对应的字符

         int  a[256];                     //记录每个出现的字符的个数

public:

         int  n;                          //叶子节点数

         void init();                                //初始化

         void CreateHTree();                      //创建huffman树

         void CreateCodeTable();                    //创建编码表

         void Encode(char *d);                           //编码

         voidDecode(char *s, char *d);               //解码

         voidprint(int i,int m);                   //打印Huffman树

         voidSelectMin(int &x, int &y, int s, int e );    //选择两个最小的节点

         voidReverse(char* s);                    //逆转编码(代码编码为叶子结点到根,而哈夫曼编码本该是根到叶子节点,所以需要逆转)

           ~ Huffman();//析构函数

};

void Huffman::init()

{

         intnNum[256]= {0};                //记录每一个字符出现的次数

         intch = cin.get(); 

         inti=0; 

         while((ch!='\r')&& (ch!='\n'))

         {

                      nNum[ch]++;                   //统计字符出现的次数

                     str[i++]= ch;                   //记录原始字符串

                     ch= cin.get();                   //读取下一个字符

         }

         str[i]='\0';

         cout<<"各个字符出现的次数:"<<endl;

   n = 0;

   for ( i=0;i<256;i++)

         {

                   if(nNum[i]>0)              //若nNum[i]==0说明该字符未出现

                   {

                            leaf[n]= (char)i;        

                            a[n]= nNum[i];  

                            n++;

                            cout<<(char)i<<"-"<<nNum[i]<<"  ";

                   }

         }

         cout<<endl;

}

void Huffman::CreateHTree()

{

         HTree= new HNode [2*n-1];          //根据权重数组a[0..n-1]初始化Huffman树

         for(int k = 0; k < n; k++)

         {

                   HTree[k].weight= a[k];

                   HTree[k].LChild= HTree[k].RChild = HTree[k].parent = -1;

         }

    int x, y;

    for (int i = n; i < 2*n-1;i++)      //开始建Huffman树

         {  

                   SelectMin(x,y, 0, i);          //从1~i中选出两个权值最小的结点

                   HTree[x].parent= HTree[y].parent = i;

                   HTree[i].weight= HTree[x].weight+ HTree[y].weight;

                   HTree[i].LChild= x;

                   HTree[i].RChild= y;

                   HTree[i].parent= -1;

         }

}

 

void Huffman::SelectMin(int &x, int&y, int s, int e )

{

         inti;

         for( i=s; i<=e;i++)

                   if(HTree[i].parent == -1)

                   {

                            x=y= i;    break;          //找出第一个有效权值x,并令y=x

                   }

   for ( ; i<e;i++)

                   if(HTree[i].parent == -1)         //该权值未使用过

                   {

                            if( HTree[i].weight< HTree [x].weight)

            {

                                     y= x;   x = i;           //迭代,依次找出前两个最小值

                            }

                            elseif ((x==y) || (HTree[i].weight< HTree [y].weight) )

                                     y= i;                 //找出第2个有效权值 y

                   }

}

void Huffman::print(int i, int m)

{

         if(HTree[i].LChild == -1)

                   cout<<setfill('')<<setw(m+1)<<leaf[i]<<setfill('-')<<setw(10-m)<<'\n';

         else

         {

                   cout<<setfill('')<<setw(m+1)<<HTree[i].weight<<setfill('-')<<setw(10-m)<<'\n';

                   print(HTree[i].LChild,m+1);

                   print(HTree[i].RChild,m+1);

         }

}

void Huffman::CreateCodeTable()

{

    HCodeTable = new HCode[n]; //生成编码表

         for(int i=0;i<n;i++) 

         {

                   HCodeTable[i].data= leaf[i];

        int child = i;                                            //孩子结点编号

        int parent =HTree[i].parent;     //当前结点的父结点编号

        int k=0;

        while(parent!=-1)

                   {

                      if(child==HTree[parent].LChild)              //左孩子标‘0’

                           HCodeTable[i].code[k]= '0';

                      else

                            HCodeTable[i].code[k]= '1' ; //右孩子标‘1’

                      k++;

                      child = parent;                                      //迭代

                      parent =HTree[child].parent;

                   }

                   HCodeTable[i].code[k]= '\0';

                   Reverse(HCodeTable[i].code);                 //将编码字符逆置,请读者自行实现

                   cout<<HCodeTable[i].data<<'\t'<<HCodeTable[i].code<<endl;

         }

}

 

void Huffman::Encode(char *d)//d为编码后的字符串

{

                char*s = str;    

                   while(*s!='\0')

                   {

                            for(int i=0;i<n;i++)

                                     if(*s == HCodeTable[i].data )

                                     {

                                               strcat(d,HCodeTable[i].code);  

                                               break;

                                     }

                            s++;

                   }

}

void Huffman::Decode(char* s, char *d)         //s为编码串,d为解码后的字符串

{      

         while(*s!='\0')

         {

                   intparent = 2*n-2;                                      //根结点在HTree中的下标

              while(HTree[parent].LChild!=-1)     //如果不是叶子结点

                   {

                            if(*s=='0')

                        parent = HTree[parent].LChild;

                  else

                           parent =HTree[parent].RChild;

                            s++;

                   }       

                   *d= HCodeTable[parent].data;

                   d++;

         }

}

void Huffman::Reverse(char* s)

{

         charch;

         intlen = strlen(s);

 

         for(int i=0;i<len/2;i++)

         {

                   ch= s[i];

                   s[i]= s[len-i-1];

                  s[len-i-1] = ch;

         }

}

Huffman::~ Huffman()

 {

         delete  []HTree;

         delete  []HCodeTable;

 }

 //测试的主函数

void main()

{

         HuffmanHFCode;

         cout<<"请输入要编码的字符串:";

         HFCode.init();

         cout<<"创建Huffman树:"<<endl;

         HFCode.CreateHTree();

         HFCode.print(2*HFCode.n-2,1);

 

         cout<<"创建Huffman编码表:"<<endl;

         HFCode.CreateCodeTable();

 

         chard[1024]={0};

         HFCode.Encode(d);

         cout<<"编码结果:"<<d<<endl;

 

         chars[1024]={0};

         HFCode.Decode(d,s);

         cout<<"解码结果:"<<s<<endl;

 

}


将代码放到visualstudio中进行测试,测试结果如下:

输进去的字符串不是空时:





代码.c文件的链接为:http://download.csdn.net/download/qq_28734159/10189212,感兴趣的可以前去下载

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值