数据结构课程设计作业 哈夫曼编码/译码器

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>

using namespace std;

typedef struct
{
    char letter, *code;
    int weight;
    int parent, lchild, rchild;
} HTNode, *HuffmanTree;
//char a[28]=" ABCDEFGHIJKLMNOPQRSTUVWXYZ";//存字符
char a[100];
int b[100];//存权值
int n=0;//字符个数
char code[100];//存输入的二进制代码。
void CreateHuffmanTree(HuffmanTree &HT, char t[], int w[])
{
    int m, s1, s2;
    m=2*n-1; //总共需要2n-1个节点
    HT=new HTNode[m+1];//开辟空间
    for(int i=0; i<n; i++)//给叶子结点赋值。
    {
        HT[i].letter=t[i];
        HT[i].weight=w[i];
    }
    for(int i=0; i<=m; i++)//初始化所有结点的父节点,左孩子、右孩子都为0.
    {
        HT[i].code='\0';
        HT[i].parent=HT[i].lchild=HT[i].rchild=-1;
    }
    for(int i=n; i<m; i++)//处理每个非叶子结点
    {
        int min1,min2;
        min1=min2=9999;
        s1=s2=-1;
        for(int k=0; k<=i-1; k++) //找到两个权值最小的结点作为左右子树的根节点构造新的二叉树。
        {
            if(HT[k].parent==-1)//只在尚未构造成二叉树的结点中查找。
            {
                if(HT[k].weight<min1)
                {
                    min2=min1;
                    s2=s1;
                    min1=HT[k].weight;
                    s1=k;
                }
                else if(HT[k].weight<min2)
                {
                    min2=HT[k].weight;
                    s2=k;
                }
            }
        }
        HT[s1].parent=i;HT[s2].parent=i;//将他们两个的父节点设置为 i;
        HT[i].lchild=s1;HT[i].rchild=s2;//把这两个分别当作 结点i 的左右孩子。
        HT[i].weight=HT[s1].weight+HT[s2].weight;//他们两个的双亲为他们两个的和。
        HT[i].letter='#';
    }
}
void CreatHuffmanCode(HuffmanTree HT)//编码。
{
    FILE *fp;
    int start, c, f;
    int i;
    char *cd=new char [n];

    cd[n-1]='\0';
    if((fp=fopen("OutMa.txt","w"))==NULL)  //输出哈夫曼编码到文件
    {
        printf("打开输出文件失败。\n");
        exit(0);
    }
    fprintf(fp,"每个字符对应的哈夫曼编码:\n");
    cout<<endl<<"每个字符对应的哈夫曼编码为:"<<endl;
    for(i=0; i<n; i++)
    {

        start=n-1;
        c=i;
        f=HT[i].parent;

        while(f!=-1)
        {
            start--;
            if(HT[f].lchild==c)
            {

                cd[start]='0';
            }
            else
            {

                cd[start]='1';
            }
            c=f;
            f=HT[f].parent;
        }

        HT[i].code=new char[n-start];
        strcpy(HT[i].code,&cd[start]);
        cout<<HT[i].letter<<": "<<HT[i].code<<endl;
        fprintf(fp,"%c  %s\n",HT[i].letter,HT[i].code);
    }
    fprintf(fp,"编码完成!\n");
    fclose(fp);
    delete cd;
}

void ReadData()//从文件中读取权值
{
    FILE *fp1;
    if(NULL== (fp1=fopen("data.txt","r")))
    {
        cout<<"error"<<endl;
        exit(1);
    }
        int i=0;
        while(fscanf(fp1,"%c%d",&a[i],&b[i])!=EOF)
            n++,i++;
            n--;
//        memset(b,0,sizeof(b));
//        char k;
//        n=27;
//        while(fscanf(fp1,"%c",&k)!=EOF)
//        {
//            for(int i=0;i<27;i++)
//            {
//                if(k==a[i])
//                b[i]++;
//            }
//        }
    fclose(fp1);
    cout<<"各个数据及其对应权值为:"<<endl;
    for(int i=0; i<n; i++)
    {
        cout<<a[i]<<":"<<b[i]<<"      ";
        if(i&&(i+1)%3==0)
            cout<<endl<<endl;
    }
}

void Yima(HuffmanTree HT,char cod[],int b)           //译码
{
    FILE *fp;
    if((fp=fopen("Translate.txt","w"))==NULL)
    {
        cout<<"打开翻译文件失败。"<<endl;
        exit(0);
    }
    char sen[100];
    char temp[50];
    char blank[]=" ";       //空白字符串
    int t=0;
    int s=0;
    int xx=0;
    for(int i=0; i<b; i++)
    {
        temp[t++]=cod[i];     //读取字符
        temp[t] = '\0';
        for(int j=0; j<n; j++)       //依次与所有字符编码开始匹配
        {

            if (!strcmp(HT[j].code,temp))                 //匹配成功
            {

                sen[s]=HT[j].letter;    //将字符保存到sen中
                s++;
                xx+=t;//用于寻找出错的位数,如果有某一位没有匹配则记录下来。
                strcpy(temp,blank);
                t=0;
                break;
            }
        }
    }
    if(t==0)      //t如果被置空了,表示都匹配出来了,打印译码
    {

        sen[s]='\0';
        cout<<"译码为:"<<endl<<sen<<endl;
        fprintf(fp,"%s",sen);
        fclose(fp);
    }
    else                              //t如果没有被置空 , 源码无法被完全匹配
    {
        cout<<"二进制源码有错,不存在此编码,从第"<<xx+1<<"位开始"<<endl;
    }
}
void InCode(HuffmanTree HT)
{
    cout<<"译码:"<<endl;
    int x,k,symbol;
    char p;
    while(1)
    {
        cout<<"请输入要译码的二进制字符串,输入'#'结束:"<<endl;
        x=1;//判断是否有非法字符只能是0 1
        k=0;//作为循环变量来使code【k】=输入的字符
        symbol=1;//判断是否输入结束
        while(symbol)//输入二进制代码。
        {
            cin>>p;
            if(p!='1'&&p!='0'&&p!='#')  //若存在其它字符,x设为0,表示输入的不是二进制数。
            {
                x=0;
            }
            code[k]=p;
            k++;
            if(p=='#')
                symbol=0;  //#号结束标志
        }
        if(x==1)
            Yima(HT,code,k-1);        //进行译码
        else
        {
            cout<<"有非法字符!"<<endl;
        }
        cout<<"输入Y继续进行编码,其他任意键退出译码:"<<endl;
        cin>>p;
        if(p=='y'||p=='Y')
            continue;
        else
            break;
    }
}
void PrintHF1(HuffmanTree HT,int k,string ss)
{
        ss+="    ";
        if(HT[k].lchild==-1||HT[k].rchild==-1)
            {
                cout<<ss;
                cout<<HT[k].letter<<endl;
                return;
            }
            PrintHF1(HT,HT[k].rchild,ss);

            cout<<ss;
            cout<<HT[k].weight<<endl;
            PrintHF1(HT,HT[k].lchild,ss);
}
void PrintHF2(HuffmanTree HT,int k)
{
    if(HT)
    {
        if(HT[k].letter=='#')
            cout<<HT[k].weight;
        else
            cout<<HT[k].letter;
        if(HT[k].lchild!=-1||HT[k].rchild!=-1)
        {
            cout<<"(";
            PrintHF2(HT,HT[k].lchild);
            cout<<",";
            PrintHF2(HT,HT[k].rchild);
            cout<<")";
        }
    }
}

void menu()
{
    cout<<endl<<endl<<endl<<endl<<"                                          哈夫曼编码/译码器                  "<<endl;
    cout<<"                    ************************************************************"<<endl;
    cout<<"                    *                                                          *"<<endl;
    cout<<"                    *             请输入以下数字选择功能                       *"<<endl;
    cout<<"                    *                                                          *"<<endl;
    cout<<"                    *   1:从文件中读取数据                                     *"<<endl;
    cout<<"                    *   2:建立哈夫曼树                                         *"<<endl;
    cout<<"                    *   3:显示哈夫曼树                                         *"<<endl;
    cout<<"                    *   4:对哈夫曼树进行编码                                   *"<<endl;
    cout<<"                    *   5:对输入代码进行译码                                   *"<<endl;
    cout<<"                    *   输入其他字符退出系统                                   *"<<endl;
    cout<<"                    *                                                          *"<<endl;
    cout<<"                    ************************************************************"<<endl<<"                    请输入数字:";
}

int main()
{
    char m;
    HuffmanTree HT;
    menu();
    int p=2*n-1;
    while(m!=5)
    {
        {
            cin>>m;
            if(m=='1')
            {
                system("cls");
                ReadData();//从文件中读取数据。
                cout<<"读入数据成功!"<<endl<<"继续输入数字选择功能:"<<endl;
            }
            else if(m=='2')
            {
                system("cls");
                CreateHuffmanTree(HT, a, b);//建立哈夫曼树。
                cout<<"建立哈夫曼树成功!"<<endl<<"继续输入数字选择功能:"<<endl;
            }
            else if(m=='4')
            {
                system("cls");
                CreatHuffmanCode(HT);//对哈夫曼树进行编码。
                cout<<"哈夫曼编码成功!可打开OutMa.txt查看。"<<endl<<"继续输入数字选择功能:"<<endl;
            }
            else if(m=='5')
            {
                system("cls");
                InCode(HT);//对输入代码进行译码。
                cout<<"译码结果同时存入Translate.txt文件,可打开查看"<<endl<<"输入6退出系统。"<<endl;
            }

            else if(m=='3')
            {
                system("cls");
                int i=0;
                while(i>=0)//找到根节点
                {

                    if(HT[i].parent==-1)
                        break;
                    else
                    {
                        i++;
                        continue;
                    }

                }
                    cout<<"凹入法显示哈夫曼树:"<<endl;
                    string ss="";
                    PrintHF1(HT,i,ss);
                    cout<<"括号法显示哈夫曼树:"<<endl;
                    PrintHF2(HT,i);
                cout<<endl<<"继续输入数字选择功能:"<<endl;
            }
            else
                break;
        }
    }
    return 0;
}

 

  • 13
    点赞
  • 120
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值