ハフマンツリーコーデック(簡易版)

#include<iostream>
#include<fstream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=200;
typedef int LL;
typedef struct HTNode* ToNode;
struct HTNode{
    LL weight;
    LL lson;LL rson;LL father;
    char c;
}HT[maxn];///到时候改成动态的
struct Querypos{
    LL s1=0;LL s2=0;///第一个为最小,第二个为次小
};
struct Answer{
    LL cnt=0;
    char bcode[maxn];
}ans[maxn];
char str[maxn];
char txtstr[maxn*maxn];
char outputTxT[maxn];
char choice[maxn];
LL outputnum=0;
LL len=0;
bool vis[maxn];
LL n;
Querypos search(LL l,LL r){
    LL minval1=0x3f3f3f3f;LL minval2=0x3f3f3f3f;
    LL minpos1=0;LL minpos2=0;
    for(LL i=l;i<=r;i++){
        if(!vis[i]){
            if(minval1>HT[i].weight){
                minval2=minval1;
                minpos2=minpos1;
                minval1=HT[i].weight;
                minpos1=i;
            }
            else if(minval2>HT[i].weight){
                minval2=HT[i].weight;
                minpos2=i;
            }
        }
    }
    Querypos t;
    t.s1=minpos1; t.s2=minpos2;
    return t;
}
///先考虑建树
void Initialzation(ToNode &now,LL n){
    if(n<=1) return;
    now=(ToNode)malloc(sizeof(HTNode));///到时候改成动态
    LL m=2*n-1;
    for(LL i=n+1;i<=m;i++){
       Querypos temp=search(1,i-1);///挑选树节点中频率最小的两个权值
       LL s1=temp.s1;LL s2=temp.s2;
       debug(s1);debug(s2);debug(i);
       vis[s1]=true;vis[s2]=true;
       HT[s1].father=i;HT[s2].father=i;
       HT[i].lson=s1;HT[i].rson=s2;
       HT[i].weight=HT[s1].weight+HT[s2].weight;
    }
}
///从叶子往根搜,没有string的返回值,C语言临时数组能传参嘛0.0
void Encoding(LL now,LL want){
    if(HT[now].father){
        LL fa=HT[now].father;
        if(HT[fa].lson==now){
            ans[want].bcode[++ans[want].cnt]='0';
        }
        else if(HT[fa].rson==now){
            ans[want].bcode[++ans[want].cnt]='1';
        }
        Encoding(HT[now].father,want);
    }
}
void Codereverse(LL now){
    for(LL i=1,j=ans[now].cnt;i<j;i++,j--){
        swap(ans[now].bcode[i],ans[now].bcode[j]);
    }
}
LL rebuild(LL rootnow,LL index){///01串还原成字符串,函数体返回当前这个字符01串的长度

    if(!HT[rootnow].lson&&!HT[rootnow].rson){
    ///if(rootnow<=n){
        char op;
        outputTxT[++outputnum]=HT[rootnow].c;
        op=HT[rootnow].c;
        cout<<op;
        return 0;
    }
    if(txtstr[index]=='1'){
        return 1+rebuild(HT[rootnow].rson,index+1);
    }
    else if(txtstr[index]=='0'){
        return 1+rebuild(HT[rootnow].lson,index+1);
    }
}
void writefileTree(LL n){///写出哈夫曼树文件
   ofstream app1("hfmTree",ofstream::out);
   for(LL i=1;i<=n*2-1;i++){///注意是2*n-1,
        app1<<(HT[i].weight)<<endl;
        app1<<(HT[i].lson)<<endl;
        app1<<(HT[i].rson)<<endl;
        app1<<(HT[i].father)<<endl;
        app1<<(HT[i].c)<<endl;
   }
   app1.close();
}
LL readfileTree(){
    ifstream iFile("hfmTree",ios::in);
    LL res=0;
    char tempstr[100];
    while(iFile.peek()!=EOF){

        if(iFile.fail()) break;

        iFile.getline(tempstr,20);
        int intStr1=atoi(tempstr);
        HT[++res].weight=intStr1;

        iFile.getline(tempstr,20);
        int intStr2=atoi(tempstr);
        HT[res].lson=intStr2;

        iFile.getline(tempstr,20);
        int intStr3=atoi(tempstr);
        HT[res].rson=intStr3;

        iFile.getline(tempstr,20);
        int intStr4=atoi(tempstr);
        HT[res].father=intStr4;

        iFile.getline(tempstr,20);
        HT[res].c=tempstr[0];
    }
    iFile.close();
    return res;
}
void writeToBeTran(LL length){///写入待翻译的文本
    ofstream app1("ToBeTran",ofstream::out);
    for(LL i=1;i<=length;i++){
        app1<<str[i];
    }
    app1.close();
}
LL readToBeTran(){
    ifstream iFile("ToBeTran",ios::in);
    LL res=0;
    char tempstr[1000];
    while(iFile.peek()!=EOF){
        if(iFile.fail()) break;

        iFile.getline(tempstr,100);
        LL length=strlen(tempstr);

        for(LL i=0;i<length;i++){
            str[++res]=tempstr[i];
        }
   }
   for(LL i=1;i<=res;i++){
    cout<<str[i];
    }
    cout<<endl;
    iFile.close();
    debug(res);
    return res;
}

void writefileCodeFile(){///写出整体文本01串
    ofstream app1("CodeFile",ofstream::out);
    for(LL i=1;i<=len;i++){
        app1<<(txtstr[i])<<endl;
        cout<<(txtstr[i]);
    }
    cout<<endl;
    app1.close();
}
LL readfileCodeFile(){///读取整体文本01串
    ifstream iFile("CodeFile",ios::in);
    char tempstr[100];
    LL res=0;
    while(iFile.peek()!=EOF){
        if(iFile.fail()) break;

        iFile.getline(tempstr,40);
        txtstr[++res]=tempstr[0];
    }
    for(LL i=1;i<=res;i++){
        cout<<txtstr[i];
    }
    cout<<endl;
    return res;
}
void writeTextfile(){
    ofstream app1("Textfile",ofstream::out);
    for(LL i=1;i<=outputnum;i++){
        app1<<outputTxT[i];
    }
    app1.close();
}
int main(void)
{

  memset(vis,0,sizeof(vis));
  cout<<"            哈夫曼编码器\n";
  while(choice[0]!='q'||choice[0]!='Q')
  {
    n=(readfileTree()+1)/2;///先把存在文件里的哈夫曼树读出来
    cout<<"功能: "<<"I(初始化,默认为存好的满字符集)"<<""<<"E(编码)"<<""<<"D(译码)"<<""<<"P(打印)"<<""<<"Q(退出)\n";
    cout<<"请输入您要选择的功能:";
    cin>>choice;
    if(choice[0]=='I'||choice[0]=='i'){///初始化
        ToNode L;
        memset(HT,0,sizeof(HT));///注意清空
        cout<<"请输入字符个数:";
        cin>>n;
        getchar();
        printf("请输入字符:");
        for(LL i=1;i<=n;i++) scanf("%c",&HT[i].c);///cin不能读空格,注意这个字符是结构体里的,所以需要结构体的&
        printf("请输入字符频度:");
        for(LL i=1;i<=n;i++) cin>>HT[i].weight;
        Initialzation(L,n);///初始化建哈夫曼树
        writefileTree(n);///把哈夫曼树存下
        n=(readfileTree()+1)/2;///更新为新的哈夫曼树
        cout<<"赫夫曼树已经创建完毕,并且已经放入hfmTree文件中!"<<endl;
    }
    else if(choice[0]=='E'||choice[0]=='e'){///编码
        getchar();
        cin.getline(str+1,maxn);///终端输入待翻译的ToBeTran
        LL strlength=strlen(str+1);
        writeToBeTran(strlength);///将TeBeTran写到文件里
        strlength=readToBeTran();///读取ToBeTran的正文
        debug(strlength);
        for(LL i=1;i<=strlength;i++){///把每个字符转换成哈夫曼编码
            for(LL j=1;j<=n;j++){
                if(str[i]==HT[j].c){
                    Encoding(j,i);
                    break;
                }
            }
        }
        for(LL i=1;i<=strlength;i++){
            Codereverse(i);///反转01串
        }
        for(LL i=1;i<=strlength;i++){
            for(LL j=1;j<=ans[i].cnt;j++){
                cout<<ans[i].bcode[j];
            }
            cout<<endl;
        }
        for(LL i=1;i<=strlength;i++){
            for(LL j=1;j<=ans[i].cnt;j++){
                txtstr[++len]=ans[i].bcode[j];///整体文本01串
            }
        }
        for(LL i=1;i<=len;i++){
            cout<<txtstr[i];
        }
        cout<<endl;
        writefileCodeFile();///写入整体文本01串
        cout<<"\n编码完毕,并且已经存入CodeFile文件!\n";
    }
    else if(choice[0]=='D'||choice[0]=='d'){///译码
        len=readfileCodeFile();///读取整体文本01串
        cout<<endl;
        for(LL i=1;i<=len;i++){
                cout<<txtstr[i];
        }
        cout<<endl;
        for(LL i=1;i<=len;i++){
            LL qiguai=rebuild(n*2-1,i);
            debug(qiguai);
            i=i+qiguai-1;///译码,从根往下搜,注意循环里还有个i++;
        }
        cout<<endl;
        writeTextfile();///把译码存到Textfile中
        cout<<"译码结果已存入Textfile.txt中\n";
    }
    else if(choice[0]=='P'||choice[0]=='p'){///打印编码文件
        cout<<"打印代码文件:"<<endl;
        len=readfileCodeFile();///读取整体文本01串
        for(LL i=1;i<=len;i++){
            cout<<txtstr[i];
            if(i!=1&&(i%50)==0) cout<<endl;
        }
        cout<<endl;
    }
    else if(choice[0]=='Q'||choice[0]=='q'){
        break;
    }
    else{
        cout<<"您没有输入正确的步骤,请重新输入!"<<endl;
    }
  }
return 0;
}

    。

おすすめ

転載: blog.csdn.net/zstuyyyyccccbbbb/article/details/111045837