【数据结构】哈夫曼树编译码器【课程设计】

简介: 【数据结构】哈夫曼树编译码器【课程设计】

(注:

本代码是使用vc++6.0完成的,不同编译器一些内部判断机制可能存在差异,导致代码不能进行正常运行


本代码直接复制下来,肯定会存在问题,原因在于文件是如何操作的,如果你一点基础都没有的话,不建议您看这篇博客)


!!!更加详细的解释在后边的代码注释中,如果程序有问题,请检查相应的文件名是否正确,


最后祝你好运,加油!!!

附上实验链接包,需要付费的,如果不想下载,请认真阅读本文,你一样也能做出来的。

https://download.csdn.net/download/L_Z_jay/68034163


课设目标:

                           

课设的功能函数:

                                           

(1) int  read_File( )   //读文件操作
 
(2) void  calculate(int chWeight[], int reRow)  //源文件中字符的频度是多少
 
(3) void  createHuffmantree(Huffman ht[], int chWeight[], int n) //创建哈夫曼树
    1) void  select (Huffman ht[], int n, int *s1, int *s2) 
                 //建立哈夫曼树,每次查找没有双亲结点且是最小的两个数
 
(4) void  huffmanCode(Huffman tree[], codetype code[], int n)  //对各个字符进行编码
 
(5) void huffmanTrans(codetype *code , int n)   //对输入的字符进行编码并保存到文件中
    1)    //将输入的字符串进行编码,
          //打印编码结果
          //并将编码结果存储进文件中
        void  memory_File(codetype *code , char b[],int n)
    2)    //将输入的字符串进行编码,
          //打印编码结果
        void printCode(codetype *code , char b[],int n)
 
(6)void huffDecode(codetype *code, int n) //对某个文件进行译码,并将译码的结果存储在另一个文件中
 
 
***main()函数为程序的入口,这个就不在详说了
 

课设代码:

//注:  
//system("pause"); 作用:是让程序暂时暂停,当你在有新的指令时,才会进行下一步
//本文传值的数字7的含义:我是从下标为0开始存储字符,且文件中只有ABCDEFG这几种字符
//若你无法解决数字7,欢迎留言,我尽力解答
//若你想了解更多,欢迎留言
//有任何的问题,都欢迎您的留言,谢谢
//我会将我所用到的文件等信息展示出来,希望可以帮助到你
//最后,谢谢您的观看!!!
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 50 
typedef struct node{
  int Weight;     //代表字符的权重
  char ch;        // 代表的是哪个字符
  int Parent;     // 双亲结点
  int Lchild;     // 左孩子
  int Rchild;     // 右孩子
}Huffman;
typedef struct code{
  char bits[N];   //字符的编码串
  int start;      //编码在位串中的起始位置
  char ch;        //存储的字符是谁?
}codetype;
int flag=0;         //判断读文件是否是首次进入读文件函数的
char container[100][100];     //从源文件中读出的内容 
char ex_container[100][100];  // 从文件中读出需要译码的内容
void select (Huffman ht[], int n, int *s1, int *s2);
void memory_File(codetype *code, char b[] ,int n);
void printCode(codetype *code, char b[] ,int n);
int  read_File( ){
    FILE *fp;
    int len,i=0;  
    //flag的作用是判断是否是首次进入读文件函数,
    //理由:因为题目的要求是我们要从文件中获取字符并统计其出现的频度
    if(flag == 0){  
      flag = 1;
      //这里是打开01.souce.txt,这个是我本机上的文件,你可能没有,
      //而且我这里用的是相对路径,相对的意思就是相对代码文件的位置在什么地方
      //如果不能正确写出来,可以在下方留言,我会尽快解答
      fp = fopen("01.souce.txt","r+");
        if(fp == NULL){
          printf("文件打开失败");
          return 0;
        }
        else
        {
          printf("恭喜恭喜,文件成功打开!!!\n");
          printf("这样您就可以进行后续步骤啦!!!\n");
          //读文件成功
          //每行的最大字符
          //这里为什么这样写请自行百度查查fgets()函数的用法和作用
          //每次读取的是一行的内容
            while(fgets(container[i],100,fp) != NULL){
                len = strlen(container[i]);
                if(i<2){
                  container[i][len-1] = '\0';
                //  printf("%d %d\n",container[i][len-1],len);
                }
                /*else{
                  printf("%d %d\n",container[i][len-1],len);
                }*/ 
                i++;
              }
          printf("\n");
          fclose(fp);
          system("pause");
          return i-1;
          
        }
    }
    else{
        //这个是打开的是里边存的是一些有效编码的文件
        fp = fopen("explain.code.txt","r+");
        if(fp == NULL){
          printf("文件打开失败");
          return 0;
        }
        else
        {
          printf("打开成功\n");
          //读文件成功
          //每行的最大字符
          //只能实现单行文本的读取
          //每次读取的是一行的内容
          while(fgets(ex_container[i],100,fp) != NULL){
            len = strlen(ex_container[i]);
            //printf("%c",ex_container[i][len-1]);
            i++;
          }
          printf("\n");
          fclose(fp);
          system("pause");
          return i-1;
          
        }
      }
}
void  calculate(int chWeight[], int reRow){
    int i,j,k;
    int len;
    for(i = 0;i <= reRow;++i){
        len = strlen(container[i]);
        for(j = 0;j < len ;++j){
          k = (int)(container[i][j] - 'A');
          chWeight[k]++;
        }
    }
    printf("各个字符的详细情况如下表示 :\n");
    printf("\t-----\n");
    printf("\t|字符|权重|\n");
    printf("\t-----\n");
    for(i = 0;i<7;i++){
      printf("\t|%2c | %2d |\n",('A'+i),chWeight[i]);
      printf("\t-----\n");
    }
    system("pause");
}
void  createHuffmantree(Huffman ht[], int chWeight[], int n){
    int m,i;
    int s1,s2;
    m = 2*n-1;
    //创建哈夫曼树
    for(i = 0;i < n;++i){
      ht[i].Weight = chWeight[i];
      ht[i].ch = 'A'+i;
      ht[i].Parent = -1;
      ht[i].Lchild = -1;
      ht[i].Rchild = -1;
    }
    for(i = n;i < m;++i){
      ht[i].Weight = 0;
      ht[i].ch = '0';
      ht[i].Parent = -1;
      ht[i].Lchild = -1;
      ht[i].Rchild = -1;
    }
    for(i = n;i<m;i++){
      select(ht,i-1,&s1,&s2);
      ht[i].Weight = ht[s1].Weight + ht[s2].Weight;
      ht[i].Lchild = s1;
      ht[i].Rchild = s2;
      ht[s1].Parent = i;
      ht[s2].Parent = i;
    }
    printf("创建完成\n");
    system("pause");
}
//字符的编码,规定左'0'右'1'
void  huffmanCode(Huffman tree[], codetype code[], int n){
     int i,c,p;
     codetype cd;  
     for(i=0;i<n;i++)
     {
      cd.start=n;
      cd.ch=tree[i].ch;
      c=i;       //从叶结点出发向上回溯
      p=tree[i].Parent;   //tree[p]是tree[i]的双亲
      while(p!=-1)
      {
       cd.start--;
       if(tree[p].Lchild==c)
      cd.bits[cd.start]='0';  //tree[i]是左子树,生成代码'0'
       else
      cd.bits[cd.start]='1';   //tree[i]是右子树,生成代码'1'
       c=p;
       p=tree[p].Parent;
      }
      code[i]=cd;    //第i+1个字符的编码存入code[i]
     }
     printf("字符编码完成\n");
     system("pause");
}
void huffmanTrans(codetype *code , int n){
    char b[100];
    int choice;
    getchar();
    printf("请输入字符串(由A-G范围的字符组成)\n");
    gets(b);
    printf("是否要将编译结果存储的文件中(1-存入文件,0-不存储)\n");
    scanf("%d",&choice);
    getchar();
    if(choice == 1){
      memory_File(code,b,n);
    }
    else if(choice == 0){
      printCode(code,b,n);
    }
    else{
      printf("非法输入,请重新进入!!!\n");
    }
    system("pause");
}
//字符译码
void huffDecode(codetype *code, int n){
  int row;
  int m;
  int i=0,j=0;
  int star;
  FILE *fp;
  row = read_File();
  //这里是文件中存在编码,我们需将它转变成相应的字符的转换过程,请独立看懂并理解
  //如果有更好的思路,欢迎下方留言,谢谢!!!
  for(i = 0;i < n;++i){
    star = code[i].start;
    if(code[i].bits[star] == ex_container[0][j]){
      m = j;
      for(j = j+1 ,star = star+1;(j < strlen(ex_container[0]) && star < n); star++,j++){
          if(code[i].bits[star] != ex_container[0][j])
              break;
        }
      if(star == n){
          fp = fopen("explain.decode.txt","a");
          if(fp == NULL)
            printf("文件打开失败,请重新尝试一次!!!");
          else{
            printf("%c ",code[i].ch);
            fprintf(fp,"%c",code[i].ch);
            i = -1;
            fclose(fp);
          }
      }
      else{
        j = m;
      }
    }
      
  }
  printf("\n");
  system("pause");
    
}
 
int main (void){
    int i,j;
    int n,reRow;
    int chWeight[10] = {0};
    Huffman ht[N];
    codetype huffCode[N];
    while(1){
      printf("\t\t\t   ***********************************\n");
      printf("\t\t\t   *1-读文件操作\t\n");
      printf("\t\t\t   *2-计算源文件中字符出现的频度\t\n");
      printf("\t\t\t   *3-建立哈夫曼树\t\n");
      printf("\t\t\t   *4-对字符编码\t\n");
      printf("\t\t\t   *5-对输入的字符进行编码并存进文件\t\n");
      printf("\t\t\t   *6-对文件进行译码并将结果存进文件\t\n");
      printf("\t\t\t   ***********************************\n");
      printf("请输入你所要进行的操作(1-6):");
      scanf("%d",&n);
      switch(n){
 
        case 1:  reRow = read_File();//读取文件中的内容
               break;
        case 2:  calculate(chWeight,reRow);//统计源文件中的各个字符的频度
               break;
        case 3:  createHuffmantree(ht,chWeight,7);//创建哈夫曼树
             printf("恭喜恭喜,哈夫曼树创建完成!!!\n");
             //printf("\t*******************************\n");
             printf("-------------------\n");
             printf("|下标|字符|权重|父结点|左结点|右结点|\n");
             for(i = 0;i<13;++i){
               //printf("\t*******************************\n");
               printf("-------------------\n");
               printf("|%3d |%3c |%3d |%4d  |%4d  |%4d  |\n",i,ht[i].ch,ht[i].Weight,ht[i].Parent,ht[i].Lchild,ht[i].Rchild);
              
             }
             printf("打印结束,真不错!!!\n\n");
             system("pause");
               break;
        case 4:  huffmanCode(ht,huffCode,7);//对各个字符进行编码
             printf("恭喜恭喜,字符编码成功,结果如下:\n");
             printf("\t-------\n");
             printf("\t|字符 |编码 |\n");
             printf("\t-------\n");
             for(i = 0;i < 7;++i){
               printf("\t|%3c  |",huffCode[i].ch);
                 for(j=huffCode[i].start;j<7;j++)
                      printf("%c",huffCode[i].bits[j]);
                printf("\n\t-------\r");
               printf("\n");
             }
             system("pause");
             break;
        case 5:  huffmanTrans(huffCode,7);//对输入的字符进行编码并保存到文件中
               break;
        case 6:  huffDecode(huffCode,7);//对某个文件进行译码,并将译码的结果存储在另一个文件中
             break;
        default :
             printf("无效输入!!!请输入(1-6)的数字\n");
             return -1;
      }
    }
    return 0;
}
//建立哈夫曼树,每次查找没有双亲结点且是最小的两个数
void  select (Huffman ht[], int n, int *s1, int *s2){
    int i,j,f = 1;
    int sum;
    for(i = 0;i < n;++i){
      for(j = i+1;j <= n;++j){
        if(ht[i].Parent != -1)
          continue;
        else{
          if(ht[j].Parent == -1){
            if(f == 1){
              sum = ht[i].Weight + ht[j].Weight;
              f = 0;
              *s1 = i;
              *s2 = j;
            }
            else {
                if((ht[i].Weight + ht[j].Weight) < sum){
                  sum = ht[i].Weight + ht[j].Weight;
                  *s1 = i;
                  *s2 = j;
                }
            }
          }
        }
      }
    }
    //交换*s1和*s2的值,使前者始终指向权重较小的下标
    if(ht[*s1].Weight > ht[*s2].Weight){
      *s1 = *s1 + *s2;
      *s2 = *s1 - *s2;
      *s1 = *s1 - *s2;
    }
}
//将输入的字符串进行编码,
//打印编码结果
//并将编码结果存储进文件中
void  memory_File(codetype *code , char b[],int n){
    int i,j=0,k;
    FILE *fp;
    fp = fopen("written.code.txt","w");
    if(fp == NULL){
      printf("文件打开失败,请重新尝试!!!");
    }
    else{
      printf("编码结果如下:\n");
      for(i=0;i<n;i++){
        if(j < strlen(b)){
            if(b[j]==code[i].ch){
              for(k=code[i].start;k<n;k++){
                printf("%c",code[i].bits[k]);
                fprintf(fp,"%c",code[i].bits[k]);
              } 
              printf(" ");
              j++; i=-1;
            }
          }
      }
      printf("\n编码结果已成功存进文件!!!\n");
        
    }
    fclose(fp);
    system("pause");
  
}
//将输入的字符串进行编码,
//打印编码结果
void printCode(codetype *code , char b[],int n){
    int i,j = 0,k;
    printf("编码结果如下:\n");
    for(i=0;i<n;i++){
      if(j < strlen(b)){
          if(b[j]==code[i].ch){
            for(k=code[i].start;k<n;k++)
                printf("%c",code[i].bits[k]);       
            j++; i=-1;
            printf(" ");
          }   
        }
    } 
    printf("\n编码结果已成功显示!!!\n");
}

运行结果截图如下:


 希望能对您有所帮助,谢谢您的观看,如果觉得对您有所帮助,请点赞,谢谢支持

相关文章
|
7月前
|
存储 算法 C语言
C语言---数据结构实验---哈夫曼树及哈夫曼编码的算法实现---图的基本操作
C语言---数据结构实验---哈夫曼树及哈夫曼编码的算法实现---图的基本操作
|
5月前
|
算法 Java
数据结构-构造哈夫曼树【详解+代码+图示】一文解惑!
数据结构-构造哈夫曼树【详解+代码+图示】一文解惑!
378 0
|
10月前
|
存储 算法
数据结构实验十二 哈夫曼树及编码
数据结构实验十二 哈夫曼树及编码
49 0
|
10月前
|
C语言
c语言数据结构-哈夫曼树
c语言数据结构-哈夫曼树
|
10月前
|
存储 算法
【开卷数据结构 】哈夫曼树
【开卷数据结构 】哈夫曼树
80 0
|
12月前
|
算法
大话数据结构--哈夫曼树及其应用
大话数据结构--哈夫曼树及其应用
95 0
|
12月前
|
C语言
C语言《数据结构》——哈夫曼树
C语言《数据结构》——哈夫曼树
343 0
数据结构——哈夫曼树
哈夫曼树 · 前言 哈夫曼树又叫做最优二叉树,可以将其看作一种特殊的二叉树。 可以说是从堆引入的哈夫曼树;堆的作用是构造最大堆和最小堆实现挑选最值删除的东西,而哈夫曼树也是寻找max和min并对其进行操作。 哈夫曼树的原理:出现频率较高的数占空间小,出现频率较低的数占空间更大。从而实现不压缩数据且节省空间的一种存储方式。
数据结构——哈夫曼树
|
算法 C语言
数据结构与算法(十四)哈夫曼树
数据结构与算法(十四)哈夫曼树
116 0
|
机器学习/深度学习 存储 算法
408数据结构学习笔记——树与二叉树的应用——哈夫曼树和哈夫曼编码、并查集
408数据结构学习笔记——树与二叉树的应用——哈夫曼树和哈夫曼编码、并查集
182 1
408数据结构学习笔记——树与二叉树的应用——哈夫曼树和哈夫曼编码、并查集