哈夫曼编码译码器,压缩比(详细运行过程)

本人小辣鸡一枚,学校的一个数据结构作业。在此记录。
编译器:codeblocks
功能:
1.选择文件建立哈夫曼树
2.建立密码本,对文件进行编码
3.选择需要进行解码的文件解码
4.按位压缩方式压缩与解压,并且显示压缩比
运行操作及效果

目录结构:
目录结构

11.txt 必须有,剩下的随意,可以最初没有。让11.txt和自己的cpp文件放到一个文件夹里面。11.txt 里面随便写点什么,我写的内容是:
bbbbbbb
AAAAAA
cc
ddddd
eeeeeeeee

下面是我的运行过程,运行完之后,22.txt存的是编码文件,33.txt存的是编码文件解码后的文件,经过验证,和11.txt内容应该相同。44.txt是22.txt按位压缩后的结果,55.txt是44.txt解码后的结果,应该和22.txt内容相同。最后得到的压缩比应该大概是1/8
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include<windows.h>
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<fstream>
using namespace std;
typedef struct HTNode{
    char data;
    int weight;
    int parent,lchild,rchild;
}HTNode,*HuffmanTree;
typedef char **HuffmanCode;
char myarr[1000]={NULL};
int mcnt;
int pData;//原文件
int nData;//压缩后的的文件
int multiple;
/*******************************************选择文件**************************************/
void ChooseFile(){
    char n[20];
    FILE *fp;
    char ch;
    int i=1;
    cout<<"输入要打开的文件"<<endl;
    cin>>n;
    fp=fopen(n,"r");
    if(fp==NULL)
        printf("打开失败!\n");
    else{
        fscanf(fp,"%c",&ch);
        while(!feof(fp)){
            myarr[i]=ch;
            fscanf(fp,"%c",&ch);
            i++;
        }
        fclose(fp);
        myarr[i]='\0';
    }
    pData=i-1;
    cout<<"打开原始文件"<<n<<"成功!";
    cout<<endl;
}
/*******************************************求文件中叶子结点的权值**************************************/
void Count(HuffmanTree &HT){//统计
    mcnt=0;
    int cnt[256]={0};
    for (int i=1;myarr[i]!='\0';i++)
        cnt[myarr[i]]++;
    for (int i=0;i<256;i++){
        if(cnt[i]>0){
            mcnt++;
        }
    }
    int m=2*mcnt-1;
    HT=new HTNode[m+1];
    int mcnt2=0;
    for (int i=0;i<256;i++){
        if(cnt[i]>0){
            mcnt2++;
            //cout<<"字符"<<(char)i<<"出现了"<<cnt[i]<<"次"<<endl;
            HT[mcnt2].weight=cnt[i];
            HT[mcnt2].data=(char)i;
        }
    }
}
/*****************************************哈夫曼编码******************************************************/
void HuffmanCODE(HuffmanTree HT, HuffmanCode &HC, int n){
    HC=new char *[n+1];
    char * cd=new char[n];
    cd[n-1]='\0';
    int start,c,f;
    for(int i=1;i<=n;i++)
    {
        start=n-1;
        c=i;
        f=HT[i].parent;
        while(f!=0)
        {
            start--;
            if(HT[f].lchild==c){
                cd[start]='0';
            }
            else{
                cd[start]='1';
            }
            c=f;
            f=HT[f].parent;
        }
        HC[i]= new char[n-start];
        strcpy(HC[i],&cd[start]);
    }
    for(int i=1;i<=mcnt;i++){
        cout<<HT[i].data<<"出现频度是:"<<HT[i].weight<<" 编码为"<<HC[i]<<endl;
    }
    delete cd;
    ofstream file;
    char fl[100];
    cout<<"输入要写入的文件"<<endl;
    cin>>fl;
    file.open(fl,ios::out);
    for(int i=1;myarr[i]!='\0';i++){
        for(int j=1;j<=mcnt;j++){
            if(myarr[i]==HT[j].data){
                    //hc[j]字符串数组
                file <<HC[j];
                break;
            }
        }
    }
    file.close();
}
/*****************************************哈夫曼译码******************************************************/
void HuffmanDECODE(HuffmanTree HT,int n){
    char decode[1000];
    FILE *fp;  //创建一个文件指针*fp
    char ch;
    int mcnt3=0;
    char f1[20];
    cout<<endl<<"输入要解码哪个文件"<<endl;
    cin>>f1;
    fp=fopen(f1,"r");
    if(fp==NULL)
        printf("打开失败!\n");
    else{
        int i=0;
        fscanf(fp,"%c",&ch);
        while(!feof(fp)){
            decode[i]=ch;
           // putchar(ch);
            fscanf(fp,"%c",&ch);
            i++;
            mcnt3++;
        }
        fclose(fp);
        decode[i]='\0';
    }
    cout<<endl;
    ofstream file;
    char fl[100];
    cout<<"输入要写入的文件"<<endl;
    cin>>fl;
    file.open(fl, ios::out);
    int i,p;
    p=2*n-1;
    for(i=0;i<=mcnt3;i++){
        if(HT[p].lchild==0&&HT[p].rchild==0){
           // printf("%c",HT[p].data);
            file <<HT[p].data;
            p=2*n-1;
        }
        if(decode[i]=='0')
            p=HT[p].lchild;
        else if(decode[i]=='1')
            p=HT[p].rchild;
    }
    file.close();
    printf("译码成功\n");
}
/********************************找到父节点不为0的两个叶子结点**********************************/
void Select(HuffmanTree &HT,int i,int &s1,int &s2){
    s1=1;
    s2=1;
    int sm1=9999;
    int sm2=9999;
    for(int j=1;j<i;j++){
        if(HT[j].parent==0){
            if(HT[j].weight<sm1){
                sm2=sm1;
                sm1=HT[j].weight;
                s2=s1;
                s1=j;
            }
            else if(HT[j].weight<sm2){
                sm2=HT[j].weight;
                s2=j;
            }
        }
    }
}
/****************************************创建哈夫曼树**************************************/
void CreatHuffmanTree(HuffmanTree &HT){

    int m=2*mcnt-1;
    for(int i=1;i<=m;i++){
        HT[i].parent=0;
        HT[i].lchild=0;
        HT[i].rchild=0;
        if(i>mcnt){
            HT[i].weight=0;
        }
    }
    for(int i=mcnt+1;i<=m;i++){
        int s1=1,s2=1;
        Select(HT,i,s1,s2);
        HT[s1].parent=i;
        HT[s2].parent=i;
        HT[i].lchild=s1;
        HT[i].rchild=s2;
        HT[i].weight=HT[s1].weight+HT[s2].weight;
    }
    cout<<"创建哈夫曼树成功!"<<endl;
    cout<<"字符   "<<"权值   "<<"双亲   "<<"左孩子   "<<"右孩子   "<<endl;
    for(int i=1;i<=m;i++){
        if(i<=mcnt){
            cout<<HT[i].data<<"        ";
        }
        else{
            cout<<"           ";
        }
        cout<<HT[i].weight<<"      ";
        cout<<HT[i].parent<<"      ";
        cout<<HT[i].lchild<<"      ";
        cout<<HT[i].rchild<<"        ";
        cout<<endl;
    }
}
/******************************二进制转十进制************************/
int binary2decimal(char str[]){
    int sum=0;
    int j=1;
    int pos = strlen(str) - 1;
    for(;pos>=0;pos--)
    {
        sum+=(str[pos]-'0')*j;
        j*=2;
    }
    return sum;
}
/*********************************压缩*********************************/
void Compress(){
    int mcount;
    char decode[1000];
    FILE *fp;  //创建一个文件指针*fp
    char ch;
    char f1[20];
    int mcnt3=0;//存储有多少个1 0
    cout<<endl<<"输入要打开哪个编码文件进行压缩?"<<endl;
    cin>>f1;
    fp=fopen(f1,"r");
    cout<<endl;
    if(fp==NULL)
        printf("打开失败!\n");
    else{
       // cout<<"编码文件的内容是:"<<endl;
        int i=0;
        fscanf(fp,"%c",&ch);
            while(!feof(fp)){
                decode[i]=ch;
              //  putchar(ch);
                fscanf(fp,"%c",&ch);
                i++;
                mcnt3++;
            }
        fclose(fp);
        decode[i]='\0';
    }
    cout<<endl;
    //已经实现把所有二进制都读入到decode数组里了,下标从0开始

    //补齐0
    int k;
    if(mcnt3%8!=0){
        multiple=8-mcnt3%8;
        for(k=0;k<multiple;k++){
            decode[mcnt3+k]='0';
        }
        decode[mcnt3+k]='\0';
    }

    char data[10];
    data[8]='\0';
    ofstream file;
    char fl[100];//解压后.txt
    cout<<"输入把编码文件压缩到哪个文件"<<endl;
    cin>>fl;
    file.open(fl,ios::out|ios::binary);

    for(mcount=0;mcount<mcnt3+k;mcount++){
        data[mcount%8]=decode[mcount];//8个存到data数组
        if((mcount+1)%8==0){
            int result=binary2decimal(data);//变成十进制
            char res=(char)result;
            file<<res;
        }
    }
    file.close();

}
/*****************************十进制转二进制**************************/
int decimal2binary(int x,int &flag,int &digit){
    int p=1,y=0,yushu;
    int cont=0;
    while(1)
    {
        yushu=x%2;
        x/=2;
        y+=yushu*p;
        p*=10;
        if(x<2)
        {
            y+=x*p;
            break;
        }
    }
    int temp=y;
    while(temp!=0)
    {
        temp/=10;
        cont++;
    }
    if(cont!=8){
        flag=1;
        digit=8-cont;
    }
    return y;
}
/*******************************解压*****************************/
void Decompression(){
    int decode[1000];
    FILE *fp;  //创建一个文件指针*fp
    char ch;
    char f1[20];
    int mcnt3=0;//存储有多少个1 0
    cout<<endl<<"输入要解压哪个文件?"<<endl;
    cin>>f1;
    fp=fopen(f1,"r");
    cout<<endl;
    if(fp==NULL)
        printf("打开失败!\n");
    else{
        int i=0;
        fscanf(fp,"%c",&ch);
        while(!feof(fp)){
            decode[i]=ch;
            int data =ch;
            if(data<0){
                data=256+data;
                decode[i]=data;
                //mcnt3++;
            }
            fscanf(fp,"%c",&ch);
            i++;
            mcnt3++;
        }
        decode[i]='\0';
        nData=i;
        fclose(fp);
    }
    ofstream file;
    char fl[100];//解压后.txt
    cout<<endl<<"输入解压后的编码文件存在哪里?"<<endl;
    cin>>fl;
    file.open(fl,ios::out|ios::binary);
    char temp[1000];
    for(int i=0;decode[i]!='\0';i++){
        int flag=0;
        int dight=0;
        int res=decimal2binary(decode[i],flag,dight);
        if(flag==1){
            for(int y=1;y<=dight;y++){
                char c='0';
                file<<c;
            }
        }
        file<<res;
    }
    file.close();

    FILE *fp2;
    fp2=fopen(fl,"r");
    cout<<endl;
    if(fp2==NULL)
        printf("打开失败!\n");
    else{
        int i=0;
        fscanf(fp2,"%c",&ch);
        while(!feof(fp2)){
            if(i<(mcnt3)*8-multiple){
                temp[i]=ch;
                fscanf(fp2,"%c",&ch);
                i++;
            }
            else{
                break;
            }
        }
        fclose(fp2);
        temp[i]='\0';
    }
    ofstream file2;
    file2.open(fl,ios::out|ios::binary);
    for(int i=0;temp[i]!='\0';i++){
            file2<<temp[i];
    }
    file2.close();
}
void setColor(unsigned short ForeColor=4,unsigned short BackGroundColor=15){
    HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE);//获取当前窗口句柄
    SetConsoleTextAttribute(handle,ForeColor+BackGroundColor*0x10);//设置颜色
}
/*********************************压缩比*********************************/
void CompressionRatio(){
    cout<<"输入压缩前的文件是?"<<endl;
    ChooseFile();
    cout<<endl;
    int decode[1000];
    FILE *fp;  //创建一个文件指针*fp
    char ch;
    char f1[20];
    int mcnt3=0;//存储有多少个1 0
    cout<<endl<<"输入压缩后的文件是?"<<endl;
    cin>>f1;
    fp=fopen(f1,"r");
    cout<<endl;
    if(fp==NULL)
        printf("打开失败!\n");
    else{
        int i=0;
        fscanf(fp,"%c",&ch);
            while(!feof(fp)){
                decode[i]=ch;
                int data =ch;
                if(data<0){
                    data=256+data;
                    decode[i]=data;
                    //mcnt3++;
                }
                fscanf(fp,"%c",&ch);
                i++;
                mcnt3++;
            }
        decode[i]='\0';
        nData=i;
        fclose(fp);
    }
    double raTio=1.0*nData/pData*100;
    cout<<"压缩比是:"<<nData<<"/"<<pData<<"="<<raTio<<"%"<<endl;
}
void HomePage(){
    cout<<"========================================================"<<endl;
    cout<<"*                *哈夫曼编码译码器*                    *"<<endl;
    cout<<"*             1、选择需要进行编码的文件                *"<<endl;
    cout<<"*             2、建立哈夫曼树                          *"<<endl;
    cout<<"*             3、建立密码本并对文件编码                *"<<endl;
    cout<<"*             4、选择需要进行解码的文件并解码          *"<<endl;
    cout<<"*             5、按位压缩方式对文件进行压缩            *"<<endl;
    cout<<"*             6、显示压缩比                            *"<<endl;
    cout<<"*             7、解压                                  *"<<endl;
    cout<<"*             8、退出                                  *"<<endl;
    cout<<"========================================================"<<endl;
}
main(){
    setColor();
    //system("color 3");
    HuffmanTree hf;
    HuffmanCode hc;
    while(1){
        HomePage();
        cout<<"输入您想进行的操作是(1-8):";
        int n;
        cin>>n;
        if(n==1){
            ChooseFile();//第一个功能
        }else if(n==2){
            Count(hf);
            CreatHuffmanTree(hf);//第二个功能
        }else if(n==3){
            HuffmanCODE(hf,hc,mcnt);//第三个功能
        }else if(n==4){
            HuffmanDECODE(hf,mcnt);//第四个功能
        }else if(n==5){
            Compress();//压缩
        }else if(n==6){
            CompressionRatio();
        }else if(n==7){
            Decompression();
        }else if(n==8){
            return 0;
        }else{
            cout<<"输入错误!";
        }
        system("pause");
        system("cls");
    }
}

哈夫曼树网上有很多的讲解。
压缩和解压的代码不多。。。
8位是256个(0-255)。。。然后char存字符。。存0-255的数字,刚好是8位,2的8次方。
所以把编码后的每8位都变成一个十进制的数字,存在char中,然后翻译再对照后翻译回十进制,再变成二进制。。。如果最后不足八位,补齐0,补成8位,解码时候注意去掉0。

欢迎各位大佬多多指教。

  • 0
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,您想了解关于C语言哈夫曼编码译码器课设和数据结构课程设计哈夫曼编码译码器的相关知识,我可以为您提供一些基本的信息。 哈夫曼编码是一种基于统计概率的编码方法,可以将每个字符使用不同长度的二进制编码表示,使得出现频率较高的字符使用较短的编码,出现频率较低的字符使用较长的编码,从而达到压缩数据的效果。 哈夫曼编码译码器的实现需要用到数据结构中的哈夫曼树和哈夫曼编码表。哈夫曼树是一种特殊的二叉树,它的叶子节点对应着每个字符,而每个字符的编码可以通过从根节点到该字符的路径上的边的方向来表示。哈夫曼编码表则是一个字符与其对应的二进制编码之间的映射表。 在C语言中,可以使用结构体来表示哈夫曼树和哈夫曼编码表。哈夫曼树的节点可以定义为一个结构体,包含字符、权值和左右子节点指针等属性。而哈夫曼编码表则可以定义为一个数组,每个元素表示一个字符与其对应的编码。 哈夫曼编码译码器的实现过程可以分为两个步骤:编码和译码。编码过程中,需要先统计原始数据中各个字符出现的频率,然后根据频率构建哈夫曼树,生成哈夫曼编码表,并将原始数据按照哈夫曼编码进行压缩。译码过程中,则需要通过哈夫曼编码表将压缩后的二进制数据还原成原始数据。 以上是关于C语言哈夫曼编码译码器课设和数据结构课程设计哈夫曼编码译码器的基本介绍,希望对您有所帮助。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值