[原]哈夫曼报文编码和译码(涨姿势!!!)

畅柯 18/11/30 20:14:07

前面已经将基本的哈夫曼编码和哈夫曼译码方法结合一些简单的应用作了总结,了解详情,本有为这块也就这样了,没得玩了!最后发现自己Too Young!Too Simple!试着做了一个题,搞了大概一天吧!才搞出来!具体题目如下:

已知某段通信报文内容,对该报文进行哈弗曼编码,并计算平均码长。
(1)统计报文中各字符出现的频度。(字符集范围为52个英文字母,空格,英文句号。报文长度<=200)
(2)构造一棵哈弗曼树,依次给出各字符编码结果。
(3)给字符串进行编码。
(4)给编码串进行译码。
(5)计算平均码长。
规定:
(1)结点统计:以ASCII码的顺序依次排列,例如:空格,英文句号,大写字母,小写字母。
(2)构建哈弗曼树时:左子树根结点权值小于等于右子树根结点权值。
(3)选择的根节点权值相同时,前者构建为双亲的左孩子,后者为右孩子。 
(4)生成编码时:左分支标0,右分支标1。
输入
第一部分:报文内容,以'#'结束。
第二部分:待译码的编码串。
输出
依次输出报文编码串、译码串、平均码长,三者之间均以换行符间隔。
平均码长,保留小数点2位。
样例输入
Data structure is the way of computer storage and organization data. A data structure is a collection of data elements that exist between one or more specific relationships.#
000111111110101111110100101010000110111100010011011000001110011110011100101011010011100001101111011001011010101011001101110010101011101011110110101000110001101001010101010001111000101001110111111101000001101010100000010111111110101110110011111101001111010111011100000011110101111000100110000111011000000111101011111101001010100001101111000100110110000011100111100111011111101110010100000100001001111000100111101011101110101010110011000000111101011111100010000100110111000111101010100111001010110111110101100010110001011110010101100110000001010000110001001111011101010111010011101010100011010111010101000001110100110111100111100011110110001111110011010000010000111110100111101011101100110110101111011111001000100
样例输出
000111111110101111110100101010000110111100010011011000001110011110011100101011010011100001101111011001011010101011001101110010101011101011110110101000110001101001010101010001111000101001110111111101000001101010100000010111111110101110110011111101001111010111011100000011110101111000100110000111011000000111101011111101001010100001101111000100110110000011100111100111011111101110010100000100001001111000100111101011101110101010110011000000111101011111100010000100110111000111101010100111001010110111110101100010110001011110010101100110000001010000110001001111011101010111010011101010100011010111010101000001110100110111100111100011110110001111110011010000010000111110100111101011101100110110101111011111001000100
Data structure is the way of computer storage and organization data. A data structure is a collection of data elements that exist between one or more specific relationships.
4.11

嗯,其实确实不是很难,就是处理的量有点庞杂,放给我这粗心的梗,甚是恼火!
这里就不说编码和译码了,之前已经说过了。主要说一下怎样按要求统计字符和给字符排序这一部分吧!至于初始化哈夫曼树的工作在这些工作做完之后才进行的。统计字符也就是遍历字符串,创建一个类专门存特定字符的,然后每个字符有它自己的频率属性,定义一个该类智能指针数组,定义一个足够大的长度,其实最长它也就二百多个,索性定义长度为1000,接着就是遍历字符串,内层遍历指针数组,是否能够匹配到当前字符,如果匹配到,就将当前指针数组中的当前字符频数加1,否则继续便利指针数组,遍历完指针数组,如果发现,指针数组中不存在该字符,将该字符添加到智能指针数组中,然后将相应字符的频数置为1,再进行字符串和指针数组的匹配和遍历,直到最后一个字符‘#’为止!
接下来就是排序,题目要求是按照空格,英文句号,26个大小写字母的谁需进行从大到小的排序!这块真不知道怎么回事,之前就是这么办的,编码不正确,导致译码也错误!最后还以为自己把题目理解错了!就把空格和句号排到最后了!发现还是不对,最后又改回来,就对了!这块简直让人难以理解!浪费了大半天时间就搞了这块,真是不值。排序,我刚开始就像着shared_ptr 之间不是可以互相赋值吗?所以就设置了一个那个字符类类型的shared_ptr变量,我这么试了,但是不行。最后,只能老规矩,就是和使用链表中的指针进行排序方法差不多,交换数据域!按字符从小到大冒泡排序!
注意,以上还要统计你智能指针数组真正的有效长度,编码时操作起来就比较方便了!
接下来就是编码和译码了!这块就不说了。
这是程序跑出来的运行截图:
在这里插入图片描述
这是源码!里面测试代码比较多,所以也比较长一点!

#include<iostream>
#include<strings.h>
#include<stdlib.h>
#include<stdio.h>
#include<memory>
#include<vector>
#include<list>
#include<string.h>
using namespace std;
enum {SIZE = 107,MAXLINE = 1000,MAX = 200};
class chars{
public:
    int a ;
    char ch;
public:
    chars():a(0),ch('\0'){}
};

class record : public chars{
public:
    chars cc ;
    int len ;
    static int calcu ;
    static void initarr(array<shared_ptr<record>,MAXLINE>&ls);   
    static void input(const char *line,array<shared_ptr<record>,MAXLINE>&ss);
    static void arraysort(array<shared_ptr<record>,MAXLINE>&ss);
    static void countchars(const char* arr,const char*zimu,array<shared_ptr<record>,MAXLINE>&ls);
    static void Cout(array<shared_ptr<record>,MAXLINE>&ls,int len );
    static void swap(shared_ptr<record>&p1,shared_ptr<record>&p2);
};

int record::calcu =0 ;
void record::Cout(array<shared_ptr<record>,MAXLINE>&ls,int len){

    int  i = 0 ;
    for(i = 0 ; i < len ; i++){
        cout<<ls[i]->cc.ch<<"     "<<ls[i]->cc.a<<endl ;
    }
}

void record::swap(shared_ptr<record>&p1,shared_ptr<record>&p2){
    shared_ptr<record>p(new record) ;
    p->cc.a = p1->cc.a;
    p->cc.ch = p1->cc.ch;
    p1->cc.a = p2->cc.a;
    p1->cc.ch = p2->cc.ch;
    p2->cc.a= p->cc.a;
    p2->cc.ch= p->cc.ch;
}

void record::arraysort(array<shared_ptr<record>,MAXLINE>&ss){
    
    int num = ss[0]->calcu ;
    int a ;
    int i,j = 0;
    shared_ptr<record>p(new record);
    for(i = 0 ; i< num ; i++){
        int flag = 0 ;
        for(j = 1 ; j <= num-i-1; j++){
            if(ss[j-1]->cc.ch > ss[j]->cc.ch){
                flag =1 ;
                swap(ss[j-1],ss[j]);
                }
            }
        if(flag ==0){
            break ;
        }
        }
}
void record::input(const char *line, array<shared_ptr<record>,MAXLINE>&ss){
    
    int i = 0 ;
    int j = 0 ;
    int count = 1 ;
    while(line[i]!='#'){
        int flag = 0; 
        for( j = 0 ; j < count ; j++){
                if(ss[j]->cc.a != 0&&ss[j]->cc.ch == line[i]){
                    flag = 1 ;
                    ss[j]->cc.a++ ;
                    break ; 
                }
        }
            
        if(flag == 0){
            ss[count-1]->cc.ch = line[i];
            ss[count-1]->cc.a  = 1 ;
            count++;
        }
        i++ ;
    }
    calcu = count-1 ;
    
    arraysort(ss);
}

void record::initarr(array<shared_ptr<record>,MAXLINE>&ls){
    int i = 0 ;
    for( i = 0 ;i < MAXLINE ;i++ ){
        shared_ptr<record>p(new record);
        p->cc.ch = '#';
        p->cc.a = 0 ;
        ls[i] = p ;           
    }
}

void record::countchars(const char* arr,const char *zimu,array<shared_ptr<record>,MAXLINE>&ss){
    int i = 0 ;
    int j = 0 ; 
    char ch ;
    int k = 0 ;
    for(i = 0 ; i < strlen(arr) ;i++){
           ch = arr[i];
           for(j = 0 ;j < 55 ;j++){
                if(zimu[j] == ch){
                    (ss[i]->a)++;
                }
           }
    }
}
class data{
public: 
    data(){}
    ~data(){}
    int a ;
    char ch ;
    list<char>s;
};


class hafu:public data,public record{
public:
    
    data da;
    int tag ;
    int l,p,r;
    static double average ;
    static int counts ;
    hafu():tag(0){}
    ~hafu(){}
    static int findmax(int s,int &kl,array<shared_ptr<hafu>,SIZE>&ls);
    static void find(int s,int& kl,int &kr,array<shared_ptr<hafu>,SIZE>&ls);
    static void init(array<shared_ptr<hafu>,SIZE>&ls,const array<shared_ptr<record>,MAXLINE>&ss);
    static void process(array<shared_ptr<hafu>,SIZE>&ls);
    static void print(const array<shared_ptr<hafu>,SIZE>&ls);
    static void makeCode(array<shared_ptr<hafu>,SIZE>&ls,char*cpline);
    static void reverse(list<char>&s);
    
    static void printCodes(array<shared_ptr<hafu>,SIZE>&ls);
    static void printaCode(array<shared_ptr<hafu>,SIZE>&ss,char*str);
    static void request(const array<shared_ptr<hafu>,SIZE>&ls);
    static void printlist( list<char>&s);
    static void transform(const array<shared_ptr<hafu>,SIZE>&ls);
    static int search(list<char>&s ,char*arr,int i);
};
double hafu::average=0;
int hafu::counts= 0;
int hafu::search(list<char>&s,char* arr,int i){

        list<char>::iterator iter ;
        int k = 0 ;
        
        for(k = 0 ;k < strlen(arr);k++ ){
            if(arr[k]!='#')break ;
        }
        int m = k ;
        int count = 0 ;
        for(iter = s.begin();iter!=s.end();iter++){
                if(*iter == arr[k]){
                    count ++ ;
                    k++ ;
                }
                else{
                    return 0;
                }
        }

            int len = s.size();
            int kk = m;
            for(k = 0 ;k< len ;k++){
                kk = m+k;
                arr[kk] ='#';
            }
            return 1 ;
}

void hafu::transform(const array<shared_ptr<hafu>,SIZE>&ls){
    
    char s[MAXLINE];
    cout<<endl;
    cin>>s;
    int i = 0,j ;
    int num = ls[0]->counts;
    int len = strlen(s);
    for(i =0 ;i< num;i++){
        i = j ;
        if(s[strlen(s)-1]=='#'){
            break;

        }
        if(search(ls[i]->da.s,s,i)){
                cout<<ls[i]->da.ch<<"";
                
                j = 0 ;
                if(i == num-1)i =0;
            }
        else{
                j++ ;
            }
        }
    cout<<endl;
}

void hafu::printlist( list<char>&s){
     list<char>::iterator iter = s.begin();
     for(iter=s.begin();iter!=s.end() ;iter++){
                cout<<*iter<<"";
    }  
}
void hafu::request(const array<shared_ptr<hafu>,SIZE>&ls){

    char arr[MAXLINE];
    int num = ls[0]->counts;
    int len = strlen(arr);
    int i ,j;
    int flag = 0 ;
    for(i = 0 ;i< len ;i++){
        for(j = 0 ;j<num;j++){
            if(ls[j]->da.ch == arr[i]){
            
                printlist(ls[j]->da.s);
                flag =1 ;
            }
        }
        if(flag==0)return ;
    }
    cout<<endl;
}


void hafu:: reverse(list<char>&s){

    int i ;
    s.reverse();
}

void hafu::makeCode(array<shared_ptr<hafu>,SIZE>&ls,char *cpline){
    int  i  =  0 ;
    int j = 0;
    int num = ls[0]->counts;
    for(j = 0 ;j < num;j++){
        int index = ls[j]->p;
         int k = j ;
         while(index){
          
            if(ls[index]->l == k){
               
                ls[j]->da.s.push_back('0');

            }
            if(ls[index]->r == k){
               
                ls[j]->da.s.push_back('1');
            }
            k = index ;
            index = ls[index]->p;
        }
        reverse(ls[j]->da.s);
    }
    printaCode(ls,cpline);
    
}

int hafu::findmax(int s,int &kl,array<shared_ptr<hafu>,SIZE>&ls){

        int i ,j;
        int temp ;
        kl = -1 ;
        int count = 0; 
        for(i = 0;i < s ;i++){
            if(kl< ls[i]->da.a && ls[i]->tag != 1){
                    kl = i;    
            }
            if(ls[i]->tag == 0)count++ ;
        }
}

void hafu::find(int s,int& kl,int &kr,array<shared_ptr<hafu>,SIZE>&ls){

    int i= 0, j = 0 ;
    int count ;
    count = findmax(s,kl,ls);
    if(count==1){
        kr = -1 ;
        return ;
    }
    
    int mins =ls[kl]->da.a+100;
    
    for(i = 0 ;i < 2 ;i++){
        int min = mins ;
        for(j = 0 ; j < s ; j++){
            if(i==0&&ls[j]->da.a < min&&ls[j]->tag == 0){
                    
                   min = ls[j]->da.a ;
                   kl = j ;
            }
            if(i==1&&ls[j]->da.a < min&& ls[j]->tag == 0){
                min = ls[j]->da.a ;
                kr = j;
                
            }
        }
        if(i == 0)ls[kl]->tag = 1 ;
        if(i == 1){
            ls[kr]->tag = 1 ;
            break ;
        }
    }
}
void hafu::print(const array<shared_ptr<hafu>,SIZE>&ls){
    int num = ls[0]->counts;
    int i = 0 ;
    for(i =0 ;i < num*2-1;i++){
        cout<<ls[i]->da.ch<<"   "<<ls[i]->da.a<<"   "<<ls[i]->p<<"   "<<ls[i]->l<<"   "<<ls[i]->r<<endl;
    }
}

void hafu::process(array<shared_ptr<hafu>,SIZE>&ls){
    int num = ls[0]->counts;
    int  j = num;
    int i ;
    int kl=-1,kr=-1 ;
    for(i =j ;i< 2*num-1;i++){
        find(i,kl,kr,ls);
        if(kr == -1)break ;
        ls[i]->da.a = ls[kr]->da.a + ls[kl]->da.a ;
        ls[i]->l = kl ;
        ls[i]->r = kr ;
        ls[kl]->p = i ;
        ls[kr]->p = i ;
    }
}

void hafu::init(array<shared_ptr<hafu>,SIZE>&ls,const array<shared_ptr<record>,MAXLINE>&ss){

    int j = 0 ;
    int num = ss[0]->calcu;
    for(j = 0;j < 2*num-1;j++){
      shared_ptr<hafu>p(new hafu);
      if(j<num)
      {  
        p->da.a= ss[j]->cc.a ;
      }
      ls[j] = p ;
    }
    int i = 0;
        
    for(i = 0 ;i< num ;i++){

        ls[i]->da.ch=ss[i]->cc.ch;
    }
    i = 0 ;
    while(1){
        if(i == 2*num-1){
            break ;
        }
        ls[i]->l = 0;
        ls[i]->r = 0;
        ls[i]->p = 0;
        if(i >= num){
            ls[i]->da.ch = '\0';
            ls[i]->da.a = 0;
            i++ ;
            continue ;
        }
        i++ ;
    }
    counts = num ;
}
void hafu::printaCode(array<shared_ptr<hafu>,SIZE>&ss,char *str){
    
    int i ,j,k = 0;
    int num = ss[0]->counts;
    for(i =0 ; i< strlen(str);i++){
        int flag = 0 ;
        for(j = 0 ;j < num ; j++){
            if(ss[j]->da.ch == str[i]){
                flag =1 ;
                printlist(ss[j]->da.s);
                average += ss[j]->da.s.size();
                break ;
            }
        }
        if(flag == 0){
            break;
        }
    }
}
void hafu::printCodes(array<shared_ptr<hafu>,SIZE>&ls){
    
    int  i =  0;
    int num = ls[0]->counts;
    for(i = 0 ; i < num ;i++){
        list<char>::iterator iter ;
        for(iter = ls[i]->da.s.begin() ; iter!=ls[i]->da.s.end();iter++){
            cout<<*iter<<"";
        }
    }
    
}
int main(){

    

    double a ;
    char line[MAXLINE],cpline[MAXLINE+1];
    array<shared_ptr<record>,MAXLINE>ls;
    scanf("%[^\n]",line);
    while('\n'!=getchar());
    strcpy(cpline,line);
    record::initarr(ls);
    record::input(line,ls);
    array<shared_ptr<hafu>,SIZE>arr ;
    hafu::init(arr,ls); 
    hafu::process(arr);
    //cout<<endl;
    hafu::makeCode(arr,cpline);
    //hafu::printaCode(arr,cpline);
    //cout<<endl;
    hafu::transform(arr);
    a = arr[0]->average*1.0/(strlen(cpline)-1);
    printf("%.2lf",a);
}

最后的统计字符平均长度,就直接调用list里面的size()方法,然后将每个字符编码长度进行累加在除上字符串的长度-1(在统计时用的是另一个原字符串的拷贝长度比源字符串长度多了个1)就行!

作者:qq_41681241 发表于 2018/11/30 20:14:07 原文链接 https://blog.csdn.net/qq_41681241/article/details/84667337
阅读:2