课程设计哈夫曼编/译码系统

41 篇文章 4 订阅
38 篇文章 2 订阅

欢迎访问我的网站:omegaxyz.com
问题描述:利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(解码)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的信息收发站设计一个哈夫曼编译码系统。

1.基本要求

(1)初始化(Initialzation)。从数据文件DataFile.data中读入字符及每个字符的权值,建立哈夫曼树HuffTree;
(2)编码(EnCoding)。用已建好的哈夫曼树,对文件ToBeTran.data中的文本进行编码形成报文,将报文写在文件Code.txt中;
(3)译码(Decoding)。利用已建好的哈夫曼树,对文件CodeFile.data中的代码进行解码形成原文,结果存入文件Textfile.txt中;
(4)输出(Output)。输出DataFile.data中出现的字符以及各字符出现的频度(或概率);输出ToBeTran.data及其报文Code.txt;输出CodeFile.data及其原文Textfile.txt;

2.重点,难点

重点:
(1)通过实验理解哈夫曼树的特征及其应用;
(2)哈夫曼树的构造算法设计;
(3)利用构造的哈夫曼树进行编码和译码。
难点:
(1)字符的哈夫曼树编码及存储;
(2)字符的译码与串的匹配算法。

3.源代码(纯C)

#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#define MAXSIZE 50

typedef struct//Huffman树的定义
{
    char name;
    unsigned int w;//权值
    unsigned int pa;//父节点
    unsigned int lch;//左子树
    unsigned int rch;//右子树
}HTnode;

typedef struct//Huffman编码
{
    int data;
    char name1;
    char *pre;
}HCnode;

int N,M;
HCnode *HC;
HTnode *HT;

void Reverse(char *str)//字符串倒置,如此便不需要反向编码
{
    int i,j;
    char ch;
    for(i=0,j=strlen(str)-1;i<j;i++,j--){
        ch=str[i];
        str[i]=str[j];
        str[j]=ch;
    }
}

int min_node(HTnode *HT,int n)//寻找Node中最小的节点
{
    int i,min;
    for(i=1;HT[i].pa;i++);//寻找根节点
    min=i;
    for(i=1;i<n;i++)
        if(!HT[i].pa)
            if(HT[i].w<HT[min].w)
                min=i;
    HT[min].pa=1;
    return min;
}

void Output_HT(HTnode *HT)//输出Huffman树
{
    int i;
    printf(" ------------------------------------\n");
    printf(" 编号  名称 权值 父节点 左子树 右子树\n");
    printf(" ------------------------------------\n");
    for(i=1;i<2*N;i++){
        printf(" |%-5d %c    %-5d %-5d %-6d %-4d|\n",i,
               HT[i].name,HT[i].w,
               HT[i].pa,HT[i].lch,
               HT[i].rch);
        printf(" ------------------------------------\n");
    }
}
//美观输出
/*void Output_HT_v2(HTnode *HT)
{
    int i;
    printf("-------------------------------------------------------------------------\n");
    printf(" 编号 名称 权值 父节点 左子树 右子树    编号 名称 权值 父节点 左子树 右子树\n");
    printf("-------------------------------------------------------------------------\n");
    for(i=1;i<2*N;i+=2){
        printf("|%-5d %c    %-5d %-5d %-6d %-4d| %-5d %c    %-5d %-5d %-6d %-4d|\n",i,
               HT[i].name,HT[i].w,
               HT[i].pa,HT[i].lch,
               HT[i].rch,i+1,HT[i+1].name,HT[i+1].w,
               HT[i+1].pa,HT[i+1].lch,
               HT[i+1].rch);
        printf("-------------------------------------------------------------------------\n");
    }
}*/

void PrintHC(HCnode *HC)//输出Huffman编码
{
    FILE *f1,*f2;
    int i=0,j=0,x=0,n=0,wpl=0;//wpl带权路径长度
    char temp[50];
    if((f1=fopen("ToBeTran.txt","r"))==NULL){//打开ToBeTran.txt
        printf("open failed!\n");exit(0);
    }
    if((f2=fopen("Code.txt","w"))==NULL){//打开Code.txt
        printf("open failed!\n");exit(0);
    }
    printf("输出Huffman编码\n");
    for(i=1;i<=N;i++)
    {
        printf("%c-->%s",HC[i].name1,HC[i].pre);
        x=strlen(HC[i].pre);
        wpl+=(HC[i].data*x);
        printf("\n");
    }
    i=0;
    while(!feof(f1)){//从ToBeTran中读取字符并写入Code
        temp[i]=fgetc(f1);
        for(j=1;j<=N;j++)
            if(temp[i]==HC[j].name1)
            {
                fprintf(f2,"%s",HC[j].pre);
            }
        i++;
    }
    fprintf(f2,"\b");
    printf("\n带权路径长度(WPL) is %d\n",wpl);
    fclose(f1);
    fclose(f2);
}

HTnode *Create()//构造Huffman树
{
    FILE *fp;
    int i,Si,Sj;//找出来的两个最小子树保存在Si和Sj里面
    HTnode *HT;
    HT=(HTnode *)malloc((2*N)*sizeof(HTnode));//给HT分配2N-1这里分配2N个
    printf("读取%d个叶节点的权值并生成Hufman Tree表格形式:\n",N);
    if((fp=fopen("DataFile.txt","rt"))==NULL){//读取DataFile的文件
        //A,10a,2b,3c,10d,11e,20f,11g,10h,20i,14j,3k,7l,15m,9n,3o,25p,6q,2r,5s,20t,21u,9v,1w,5x,6y,8z,3 ,28!,8
        printf("can not find file DataFile failed!\n");exit(0);
    }
    for(i=1;i<=N;i++)
    {
        fscanf(fp,"%c,%d",&HT[i].name,&HT[i].w);//将Data的名称和权值赋值给HT
        HT[i].lch=HT[i].rch=HT[i].pa=0;//初始化
    }
    printf("\n");
    for(;i<=M;i++)
        HT[i].lch=HT[i].rch=HT[i].pa=HT[i].w=0;//对其它多余的树进行初始化
    for(i=N+1;i<=M;i++)
    {
        Si=min_node(HT,i);//寻找最小的节点
        Sj=min_node(HT,i);//同上
        HT[i].w=HT[Si].w+HT[Sj].w;//创建
        HT[Si].pa=HT[Sj].pa=i;
        HT[i].lch=Si;HT[i].rch=Sj;
    }
    return HT;
}

HCnode *Coding(HTnode *HT)//Huffman编码
{
    int i,j,c,f;
    HCnode *HC;
    char data[MAXSIZE];
    HC=(HCnode *)malloc(N*sizeof(HCnode));//叶子节点的个数
    for(i=1;i<=N;i++)
    {
        memset(data,'\0',MAXSIZE);
        HC[i].name1=HT[i].name;//将树的名称给HC
        HC[i].data=HT[i].w;//权值复制
        for(c=i,j=0,f=HT[c].pa;f;c=f,f=HT[f].pa,j++)//根节点循环终止,HC[f]的父节点给f,反向Huffman编码
        {
            if(HT[f].lch==c)data[j]='0';//左子树为0,右子树为1
            else data[j]='1';
        }
        HC[i].pre=(char *)malloc((strlen(data)+1)*sizeof(char));
        Reverse(data);//逆置Huffman编码
        for(j=0;j<strlen(data)+1;j++)
            HC[i].pre[j]=data[j];
        HC[i].pre[j]='\0';//将Huffman编码给HC.pre[]
    }
    return HC;
}

void Decoding(HTnode *HT)//解码
{
    FILE *fp1,*fp2;
    char ch[50];
    char cod[200];
    int f,root,i=0,j=0;
    if((fp1=fopen("CodeFile.txt","r"))==NULL){
        printf("open file failed");exit(0);
    }
    if((fp2=fopen("Textfile.txt","w"))==NULL){
        printf("open file failed");exit(0);
    }
    while(!feof(fp1)){//将Codefile的文件给cod[]
        fscanf(fp1,"%c",&cod[i]);
        i++;
    }
    i=1;
    while(HT[i].pa){i++;}//寻找根节点
    root=i;
    i=0;
    while(cod[i]!='\b')//结尾
    {
        f=root;
        while(HT[f].lch!=NULL)//不为空
        {
            if(cod[i]=='0') f=HT[f].lch;
            else f=HT[f].rch;
            i++;
        }
        ch[j++]=HT[f].name;
    }
    ch[j]='\0';
    printf("\nCodeFile.txt解码为:%s\n",ch);i=0;
    fprintf(fp2,"%s\b",ch);
    fclose(fp1);
    fclose(fp2);
}

void Output()   //输出Textfile.txt、ToBeTran.txt、Code.txt、CodeFile.txt、Textfile.txt
{
    int c;
    char b;
    FILE *fp1,*fp2,*fp3,*fp4,*fp5;
    if((fp1=fopen("Datafile.txt","r"))==NULL){
        printf("open file0 failed!\n");exit(0);
    }
    if((fp1=fopen("Datafile.txt","r"))==NULL){
        printf("open file0 failed!\n");exit(0);
    }
    if((fp2=fopen("ToBeTran.txt","r"))==NULL){
        printf("open file ToBeTran failed!\n");exit(0);
    }
    if((fp3=fopen("Code.txt","r"))==NULL){
        printf("open file Code failed!\n");exit(0);
    }
    if((fp4=fopen("CodeFile.txt","r"))==NULL){
        printf("open file CodeFile failed!\n");exit(0);
    }
    if((fp5=fopen("Textfile.txt","r"))==NULL){
        printf("open file Textfile failed!\n");exit(0);
    }
    printf("\n输出DataFlie中的字符及其权值:\n");
    while(!feof(fp1)){
        fscanf(fp1,"%c,%d", &b,&c);
        printf("'%c'---%d\n",b,c);
    }
    printf("\n\n输出ToBeTran:\n");
    while(!feof(fp2)){
        fscanf(fp2,"%c",&b);
        printf("%c",b);
    }
    printf("\n\n输出Code.txt:\n");
    while(!feof(fp3)){
        fscanf(fp3,"%c",&b);
        printf("%c",b);
    }
    printf("\n\n输出CodeFile.txt:\n");
    while(!feof(fp4)){
        fscanf(fp4,"%c",&b);
        printf("%c",b);
    }
    printf("\n\n输出Textfile.txt:\n");
    while(!feof(fp5)){
        fscanf(fp5,"%c",&b);
        printf("%c",b);
    }
    printf("\n");
    fclose(fp1);fclose(fp2);fclose(fp3);fclose(fp4);fclose(fp5);
}

void Output2(int n)   //输出Textfile.txt、ToBeTran.txt、Code.txt、CodeFile.txt、Textfile.txt
{
    int c;
    char b;
    FILE *fp1,*fp2,*fp3,*fp4,*fp5;
    switch(n)
    {
        case 1:printf("\n输出DataFlie中的字符及其权值:\n");
                if((fp1=fopen("Datafile.txt","r"))==NULL){
                printf("open file0 failed!\n");exit(0);}
                while(!feof(fp1)){fscanf(fp1,"%c,%d", &b,&c);
                printf("'%c'---%d\n",b,c);}fclose(fp1);break;
        case 2:printf("\n\n输出ToBeTran:\n");
                if((fp2=fopen("ToBeTran.txt","r"))==NULL){
                printf("open file ToBeTran failed!\n");exit(0);}
                while(!feof(fp2)){fscanf(fp2,"%c",&b);
                printf("%c",b);}fclose(fp2);break;
        case 3:printf("\n\n输出Code.txt:\n");
            if((fp3=fopen("Code.txt","r"))==NULL){
                printf("open file Code failed!\n");exit(0);}
                while(!feof(fp3)){fscanf(fp3,"%c",&b);
                printf("%c",b);}fclose(fp3);break;
        case 4:printf("\n\n输出CodeFile.txt:\n");
                if((fp4=fopen("CodeFile.txt","r"))==NULL){
                printf("open file CodeFile failed!\n");exit(0);}
                while(!feof(fp4)){fscanf(fp4,"%c",&b);
                printf("%c",b);}fclose(fp4);break;
        case 5:printf("\n\n输出Textfile.txt:\n");
                if((fp5=fopen("Textfile.txt","r"))==NULL){
                printf("open file Textfile failed!\n");exit(0);}
                while(!feof(fp5)){fscanf(fp5,"%c",&b);
                printf("%c",b);}fclose(fp5);break;
        default:printf("ERROR!");
    }
    printf("\n");
}

void msgbox()
{
    printf("--------------------------------------------------\n");
    printf("-          Huffman编码与解码                     -\n");
    printf("-            主要文件介绍    *为写入             -\n");
    printf("- *1.Code      一串01数字码,解码后可以看出明文  -\n");
    printf("- 2.CodeFile   一串01数字码,解码后可以看出明文  -\n");
    printf("- 3.DataFile   单个字符及字符的权重              -\n");
    printf("- *4.TextFile   一个英文句子                     -\n");
    printf("- 5.ToBeTran   一个英文句子                      -\n");
    printf("--------------------------------------------------\n");
}

int main()
{
    int i;
    FILE *fp;
    char **code;//构建一个二维数组解码用
    char ope;
    msgbox();
    printf("根据Data文件请输入分配的空间(此文件输入>29):");
    while(scanf("%d",&N))
    {
        if(N>0&&N<=500){
        M=2*N-1;
        code=(char**)malloc(100*sizeof(char));
        for(i=0;i<N;i++)
            code[i]=(char *)malloc(8*sizeof(char));
        Output2(1);
        printf("读取DataFile中的字符及权值,建立Huffman树:\n");
        HT=Create();
        Output_HT(HT);
        printf("\n");
        printf("对Huffman树进行编码:\n");
        HC=Coding(HT);
        PrintHC(HC);
        printf("-------------------------------------------------------------------\n");
        printf("将ToBeTran的内容改写成编码写入Code.txt\n");
        Output2(2);
        Output2(3);
        printf("-------------------------------------------------------------------\n");
        printf("对文件CodeFile.data中的代码进行解码形成原文,结果存入文件Textfile.txt中\n");
        Decoding(HT);
        Output2(4);
        Output2(5);
        printf("-----------------------------总输出函数--------------------------------\n");
        Output();
        break;
        }
        else printf("请重新输入:\n");
    }
    return 0;
}

这里写图片描述
这里写图片描述

基于C语言的哈夫曼/译码系统是一种数据压缩技术,它通过将频率较高的字符用较短的二进制串表示,来减少数据的存储空间。以下是该系统设计与实现的简要介绍。 首先,设计哈夫曼编码的核心数据结构哈夫曼树和编码表。 1. 哈夫曼树:使用树的数据结构每个节点包含一个字符和它的频率。通过合并频率最低的两个节点,构建哈夫曼树,直到所有节点合并完成。 2. 编码表:根据构建好的哈夫曼树,生成字符和对应二进制串的编码表。 其次,实现哈夫曼编码译码的功能函数: 1. 编码函数:读取输入文件,根据字符编码对应的编码以二进制形式写入输出文件。 2. 译码函数:读取输入文件的二进制数据,根据编码表,将连续的二进制数据转换为字符并写入输出文件。 最后,写用户界面和文件处理模块: 1. 用户界面:提供命令行或图形界面,以选择输入文件、输出文件的路径和操作,如编码译码。 2. 文件处理:负责读取输入文件的字符,统计频率,生成哈夫曼树和编码表,将编码后的数据写入输出文件。 设计这个系统需要对C语言和数据结构有较好的掌握,包括树、队列、文件处理等相关知识。在实现,要注意处理频率相同的字符,以及处理文件读写异常等错误情况。 通过该系统,可以将输入文件的大小大大减少,提高存储效率。同时,哈夫曼/译码技术在图像和音频等领域也具有广泛的应用。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值