还是数据结构,哈夫曼编码

哈夫曼编译码其实我觉得是很麻烦的,我做的时候老是出一些小错误,是我找错找的很久的一个程序,而且我做的时候对文件操作完全没概念,所有的函数都是慢慢从各种途径找出来的,当时做的不知道多纠结了。不多说,看源码

#include<stdio.h>
#include<iostream>
#include<stdlib.h>

typedef struct{
    char character;           //字符
    int weight;               //权值
    int parent,lchild,rchild; //双亲以及左孩子右孩子的信息
}HTNode,*HuffermanTree;

typedef char **HuffermanCode;

/*全局变量*/
char *a;                      //动态生成数组,用来存放输入的字符
int *w;                       //动态生成数组,用来存放输入的字符的权值


void Input(int &n);
void saveNumber(int n);
void CreatHuffermanTree(HuffermanTree &HT,int *w,char *a,int n);

void readFile(HuffermanTree &HT,int n);              //从hfmTree.txt文件中读入HuffermanTree
void huffermanCoding(HuffermanTree HT,HuffermanCode &HC,int n);
void showEveryCode(HuffermanTree HT,HuffermanCode HC,int n);
void Article(HuffermanTree HT,HuffermanCode HC,int &wordNumber,int n);
void translation(HuffermanTree HT,int wordNumber,int n);
void CodePrint();
void TreePrinting(HuffermanTree HT,int n);
void getNumber(int &n);



void main()
{
    char x='N';                   //用于判断是否结束
    int n;                        //n是字符个数
    int wordNumber;           //文章字符数
    HuffermanTree HT=NULL;         //定义haffermantree
    HuffermanCode HC;
    while(x!='Q')
    {   
        system("cls");
        printf("/t/t哈夫曼编译码器/n");
        printf("/t指令说明:/n");
        printf("/tI:初始化(Initialization)/n");
        printf("/tE:编码(Encoding)/n");
        printf("/tD:译码(Decoding)/n");
        printf("/tP:印代码文件(Print)/n");
        printf("/tT:印哈夫曼树(Tree printing)/n");
        printf("/tQ:退出(Quit)/n");
        printf("*******************************************/n/n");
        printf("请输入指令(按回车确认): ");
        scanf("%c",&x);

        switch(x)
        {
        case 'I':
            {
                Input(n);
                saveNumber(n);
                CreatHuffermanTree(HT,w,a,n);
            }
            break;
        case 'E':
            {
                if(HT==NULL)
                {
                    getNumber(n);
                    readFile(HT,n);
                }
                huffermanCoding(HT,HC,n);
                showEveryCode(HT,HC,n);
                Article(HT,HC,wordNumber,n);
            }
            break;
        case 'D':
            {
                translation(HT,wordNumber,n);
            }
            break;
        case 'P':
            CodePrint();
            break;
        case 'T':
            TreePrinting(HT,n);
            break;
        case 'Q':
            break;
        default:
            {
                printf("您输入的指令有错误,请看指令说明重新输入!");
                getchar();
                getchar();
                break;
            }
        }
    }
}


void Input(int &n)
{
    printf("请输入字符个数:");
    scanf("%d",&n);
   
    a=(char*)malloc(n*sizeof(char));                   //动态分配空间存放n个字符
    w=(int*)malloc(n*sizeof(int));                     //动态分配空间存放n个字符的权值
    for(int i=0;i<n;i++)
    {
        getchar();
        printf("请输入第%d个字符:",i+1);
        scanf("%c",&a[i]);
        printf("请输入该字符的权值:");
        scanf("%d",&w[i]);
    }
}

void saveNumber(int n)
{
    FILE *fp;
    fp=fopen("number.txt","w");
    if(!fp)
    {
        printf("文件打开失败!");
        exit(0);
    }
    fwrite(&n,sizeof(int),1,fp);
    fclose(fp);
}

void Select(HuffermanTree &HT,int n,int &s1,int &s2)    //s1是最小的一个数,s2倒数第二小
{
    int min,secondmin;
    for(int i=1;i<=n;i++)
    {
        if(HT[i].parent==0)
        {
            min=i;
            break;
        }
    }
    for(i=1;i<=n;i++)
    {
        if((HT[i].parent==0)&&(HT[i].weight<HT[min].weight))
        {
            min=i;
        }
    }
    s1=min;

    for(i=1;i<=n;i++)
    {
        if((HT[i].parent==0)&&(i!=min))
        {
            secondmin=i;
            break;
        }
    }
    for(i=1;i<=n;i++)
    {
        if((HT[i].parent==0)&&(HT[i].weight<HT[secondmin].weight)&&(i!=min))
        {
            secondmin=i;
        }
    }
    s2=secondmin;

}


void CreatHuffermanTree(HuffermanTree &HT,int *w,char *a,int n)
{
    int m;
    int s1,s2;
    HuffermanTree p;
    FILE *fp;

    if(n<=1) return;
    m=2*n-1;
    HT=(HuffermanTree)malloc((m+1)*sizeof(HTNode));           //0号单元未用
    p=HT;

    for(int i=1;i<=n;i++)
    {
        p[i].character=a[i-1];
        p[i].weight=w[i-1];
        p[i].parent=0;
        p[i].lchild=0;
        p[i].rchild=0;
    }
    for(i=n+1;i<=m;i++)
    {
        p[i].character='*';
        p[i].weight=0;
        p[i].parent=0;
        p[i].lchild=0;
        p[i].rchild=0;
    }
    for(i=n+1;i<=m;i++)                    //构造哈夫曼树
    {
        Select(HT,i-1,s1,s2);
        HT[s1].parent=i;
        HT[s2].parent=i;
        HT[i].lchild=s2;
        HT[i].rchild=s1;
        HT[i].weight=HT[s2].weight+HT[s1].weight;
    }

    fp=fopen("hfmTree.txt","w");              //保存哈夫曼树
    if(!fp)
    {
        printf("文件打开错误!");
        exit(0);
    }
    for(i=1;i<=m;i++)
    {
        fwrite(&HT[i],sizeof(HTNode),1,fp);
    }
    fclose(fp);
    printf("哈夫曼树已经成功构建,并保存在hfmTree.txt文件中。按任意键继续...");
    getchar();
    getchar();
}

void getNumber(int &n)
{
    FILE *fp;
    fp=fopen("number.txt","r");
    fread(&n,sizeof(int),1,fp);
    fclose(fp);
}



void readFile(HuffermanTree &HT,int n)
{
    FILE *fp;
    int m=2*n-1;
    fp=fopen("hfmTree.txt","r");
    if(!fp)
    {
        printf("文件打开错误!");
        exit(0);
    }
    HT=(HuffermanTree)malloc((m+1)*sizeof(HTNode));
    for(int i=1;i<=m;i++)
    {
        fread(&HT[i],sizeof(HTNode),1,fp);
    }
}

void huffermanCoding(HuffermanTree HT,HuffermanCode &HC,int n)
{
    int start;
    int c,f;
    HC=(HuffermanCode)malloc((n+1)*sizeof(char*));             //分配n个字符编码的头指针向量,0号单元不用
    char *code=(char*)malloc(n*sizeof(char));                  //分配求编码的工作空间
    code[n-1]='/0';                                            //编码结束符,n个叶子结点最长编码为n-1位
    for(int i=1;i<=n;i++)
    {
        start=n-1;
        for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent) //子叶到根逆向求编码
        {
            if(HT[f].lchild==c)
            {
                code[--start]='1';
            }
            else
            {
                code[--start]='0';
            }
        }
        HC[i]=(char*)malloc((n-start)*sizeof(char));
        strcpy(HC[i],&code[start]);
    }
    free(code);
}


void showEveryCode(HuffermanTree HT,HuffermanCode HC,int n)
{
    for(int i=1;i<=n;i++)
    {
        printf("%c的哈夫曼编码是:",HT[i].character);
        printf("%s",HC[i]);
        printf("/n");
    }
}

void Article(HuffermanTree HT,HuffermanCode HC,int &wordNumber,int n)
{
    FILE *fp;
    wordNumber=0;
    char article[200];
   
    printf("请输入英文文章#号结束:/n");
    article[0]=getchar();
    while(article[wordNumber]!='#')
    {
        wordNumber++;
        article[wordNumber]=getchar();
    }

    fp=fopen("CodeFile.txt","w");
    if(!fp)
    {
        printf("打开文件失败!");
        exit(0);
    }

    for(int i=0;i<wordNumber;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(article[i]==HT[j].character)
            {
                fputs(HC[j],fp);
            }
        }
    }
    fclose(fp);
    printf("文章已经编码完成,保存在CodeFile.txt文件中。按任意键继续...");
    getchar();
    getchar();
}



void translation(HuffermanTree HT,int wordNumber,int n)
{
    FILE *fp1,*fp2;
    char article[200];
    char a;
    int p;                //临时变量
    int c;                //标记根结点
    fp1=fopen("CodeFile.txt","r");
    if(!fp1)
    {
        printf("文件无法打开!");
        exit(0);
    }

    fp2=fopen("TextFile.txt","w");
    if(!fp2)
    {
        printf("文件无法打开!");
        exit(0);
    }

    for(int i=1;i<=2*n-1;i++)
    {
        if(HT[i].parent==0)
            c=i;
    }
    for(i=0;i<wordNumber-1;i++)
    {
        p=c;
        while(HT[p].lchild!=0||HT[p].rchild!=0)
        {
            a=fgetc(fp1);      //从流中读取一个字符
            if(a=='0')
                p=HT[p].rchild;
            else
                p=HT[p].lchild;
        }
        article[i]=HT[p].character;
        fputc(article[i],fp2);
    }
    fclose(fp1);
    fclose(fp2);
    printf("翻译后:");
    for(i=0;i<wordNumber-1;i++)
    {
        printf("%c",article[i]);
    }
    printf("/n");
    printf("译码已经完成,结果存入TextFile.txt文件中。按任意键继续...");
    getchar();
    getchar();
}

void CodePrint()
{
    FILE *fp1,*fp2;
    char a;
    fp1=fopen("CodeFile.txt","r");
    if(!fp1)
    {
        printf("文件打开失败1");
        exit(0);
    }
    fp2=fopen("CodePrin.txt","w");
    a=fgetc(fp1);
    while(a!=EOF)
    {
        for(int i=0;i<50;i++)
        {
            fputc(a,fp2);
            printf("%c",a);
            a=fgetc(fp1);
            if(a==EOF)
                break;
        }
        if(a!=EOF)
        {
            fputc('/n',fp2);
            printf("/n");
        }
    }
    fclose(fp1);
    fclose(fp2);
    printf("/n此字符形式的编码已经存入CodePrin.txt文件中。按任意键继续...");
    getchar();
    getchar();
}

void Bianli(HuffermanTree HT,FILE *fp,int c)
{
    int p,q;
    int k=0;
    p=c;
    q=c;
    while(HT[p].parent!=0)
    {     
        p=HT[p].parent;
        k++;
    }
    if(k==0)
    {
        printf("%c",HT[c].character);
        fputc(HT[c].character,fp);
        printf("/n");
        fputc('/n',fp);
    }
    else if(k==1)
    {
        printf("┠");
        printf("%c",HT[c].character);
        fputc('-',fp);
        fputc(HT[c].character,fp);
        printf("/n");
        fputc('/n',fp);
    }
    else
    {
        for(int i=0;i<k-1;i++)
        {
            printf("┃");
            fputc('|',fp);
        }
        printf("┠");
        printf("%c",HT[c].character);
        fputc('-',fp);
        fputc(HT[c].character,fp);
        printf("/n");
        fputc('/n',fp);
    }
    if(HT[c].lchild!=0)
    {
        q=HT[c].lchild;
        Bianli(HT,fp,q);
    }
    if(HT[c].rchild!=0)
    {
        q=HT[c].rchild;
        Bianli(HT,fp,q);
    }
}


void TreePrinting(HuffermanTree HT,int n)
{
    FILE *fp;
    int c;        //指示根结点
    fp=fopen("TreePrint.txt","w");
    for(int i=1;i<=2*n-1;i++)
    {
        if(HT[i].parent==0)
        {
            c=i;
            break;
        }
    }
    Bianli(HT,fp,c);
    fclose(fp);
    printf("哈夫曼树的直观形式凹形表已经存入文件TreePrint.txt中。按任意键继续...");
    getchar();
    getchar();
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值