【软件开发综合实验】文本压缩软件

使用哈夫曼编码对文本文件进行压缩。

#include<cstdio>
#include<cstring>
#include<vector>
#include<string>
#include<queue>
#include<map>
#include<conio.h>
#include<windows.h>
#include<algorithm>
#include<iostream>
using namespace std;
typedef unsigned char uc;
typedef unsigned long long ull;
string s2;
vector<int>G[512];//用vector存储哈夫曼树
typedef vector<int>::iterator ITER;
string anss[256];
typedef pair<int,int> data;//堆中存储的数据类型为pair<int,int>
#define N 1000000
uc sp[N+5];
int lenp;
char s[N+5],table[256];
int n,m;
int cnts[256];//记录各字符出现频率
int ReadIn(FILE* fp);//读入文本文件,返回其总长度
void Freq_stats();//统计各字符出现频率
void dfs(int U,string s);//深度优先遍历哈夫曼树,生成每个字符的哈夫曼编码
void HuffmanCoding();//用堆实现哈夫曼编码主过程
int main(){
    int op;
    char ch;
    while(1){
        system("cls");
        printf("请输入对应数字选择您想要的功能:\n");
        printf("1.压缩当前目录下的test.txt文件到test.comp,并且输出各字符出现频率以及编码表。\n");
        printf("2.解压当前目录下的test.comp文件,并且输出原文本到test2.txt。\n");
        printf("3.退出程序。\n");
        scanf("%d",&op);
        if(op==1){
            FILE* fp=fopen("test.txt","r");
            n=ReadIn(fp);
            puts("");
            fclose(fp);
            Freq_stats();
            puts("");
            HuffmanCoding();
            puts("");
            fp=fopen("test.comp","wb");
            s2.clear();
            for(int i=0;i<n;++i){
                s2+=anss[s[i]];
            }
            cout<<"以二进制形式查看该压缩后的文件:"<<"\n"<<s2<<"\n\n";
            lenp=0;
            int tmp=0;
            for(int i=0;i<s2.length();++i){
                tmp=tmp*2+s2[i]-'0';
                if(i%8==7 || i==s2.length()-1){
                    sp[lenp++]=tmp;
                    tmp=0;
                    if(i==s2.length()-1){
                        sp[lenp++]=(i+1)%8;
                        if(!sp[lenp-1]){
                            sp[lenp-1]=8;
                        }
                    }
                }
            }
            uc t[1];
            t[0]=m;
            fwrite(t,sizeof(uc),1,fp);
            for(int i=0;i<m;++i){
                fwrite(table+i,sizeof(char),1,fp);
                ull tt[1]={0};
                for(int j=0;j<anss[table[i]].length();++j){
                    tt[0]=tt[0]*2+anss[table[i]][j]-'0';
                }
                char tmp_len[1]; tmp_len[0]=anss[table[i]].length();
                fwrite(tmp_len,sizeof(char),1,fp);
                fwrite(tt,sizeof(ull),1,fp);
            }
            fwrite(sp,sizeof(uc),lenp,fp);
            fclose(fp);
            printf("按任意键继续");
            while(!kbhit());
            ch=getch();
            if(ch==-32){
                getch();
            }
        }
        else if(op==2){
            FILE* fp=fopen("test.comp","rb");
            char M[1];
            fread(M,sizeof(char),1,fp);
            m=M[0];
            memset(cnts,0,sizeof(cnts));
            ull anss[256]={0};
            char x[1];
            ull y[1];
            char tlen[1];
            map<string,char>ma;
            for(int i=1;i<=m;++i){
                fread(x,sizeof(char),1,fp);
                fread(tlen,sizeof(char),1,fp);
                fread(y,sizeof(ull),1,fp);
                string ts="";
                for(int j=tlen[0]-1;j>=0;--j){
                    ts+=(char)((y[0]>>j)&1);
                }
                ma[ts]=x[0];
            }
            memset(sp,0,sizeof(sp));
            fread(sp,sizeof(uc),N,fp);
            fclose(fp);
            string now="";
            FILE* fp2=fopen("test2.txt","w");
            int nn;
            for(int i=N+4;i>=0;--i){
                if(sp[i]){
                    nn=i;
                    break;
                }
            }
            puts("解压后的原文本为:");
            for(int i=0;i<nn;++i){
                int lim=(i==nn-1 ? sp[nn] : 8);
                for(int j=0;j<lim;++j){
                    now+=(char)((sp[i]>>(lim-1-j))&1);
                    if(ma[now]){
                        putchar(ma[now]);
                        fprintf(fp2,"%c",ma[now]);
                        now.clear();
                    }
                }
            }
            fclose(fp2);
            puts("");
            printf("按任意键继续");
            while(!kbhit());
            ch=getch();
            if(ch==-32){
                getch();
            }
        }
        else{
            break;
        }
    }
    return 0;
}
int ReadIn(FILE* fp){
    int len=0;
    while(!feof(fp)){
        fgets(s+len,N,fp);
        len+=strlen(s+len);
    }
    puts("原文本:");
    puts(s);
    return len;
}
void Freq_stats(){
    m=0;
    memset(cnts,0,sizeof(cnts));
    for(int i=0;i<n;++i){
        ++cnts[s[i]];
    }
    puts("各字符出现频率:");
    for(int i=0;i<256;++i){
        if(cnts[i]){
            table[m++]=(char)i;
            if(i!='\n'){
                printf("%c %d\n",i,cnts[i]);
            }
            else{
                printf("\\n %d\n",cnts[i]);
            }
        }
    }
}
void dfs(int U,string s){
    if(U<256){
        anss[U]=s;
    }
    char c='0';
    for(ITER it=G[U].begin();it!=G[U].end();++it,++c){
        dfs(*it,s+c);
    }
}
void HuffmanCoding(){
    for(int i=0;i<512;++i){
        G[i].clear();
    }
    priority_queue<data,vector<data>,greater<data> >Heap;
    for(int i=0;i<256;++i){
        if(cnts[i]){
            Heap.push(make_pair(cnts[i],i));
        }
    }
    for(int i=1;i<m;++i){
        data x=Heap.top(); Heap.pop();
        data y=Heap.top(); Heap.pop();
        G[255+i].push_back(x.second);
        G[255+i].push_back(y.second);
        sort(G[255+i].begin(),G[255+i].end());
        Heap.push(data(x.first+y.first,255+i));
    }
    dfs(255+m-1,"");
    puts("给各个字符分配的零一编码:");
    for(int i=0;i<256;++i){
        if(cnts[i]){
            if(i!='\n'){
                cout<<(char)i<<' '<<anss[i]<<endl;
            }
            else{
                cout<<"\\n "<<anss[i]<<endl;
            }
        }
    }
}
posted @ 2017-12-30 20:19  AutSky_JadeK  阅读(373)  评论(0编辑  收藏  举报
TVアニメ「Charlotte(シャーロット)」公式サイト TVアニメ「Charlotte(シャーロット)」公式サイト