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

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

(注:

本代码是使用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");
}

运行结果截图如下:


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

相关文章
|
存储 算法 C语言
C语言---数据结构实验---哈夫曼树及哈夫曼编码的算法实现---图的基本操作
C语言---数据结构实验---哈夫曼树及哈夫曼编码的算法实现---图的基本操作
|
2月前
|
存储 C语言
数据结构基础详解(C语言): 树与二叉树的应用_哈夫曼树与哈夫曼曼编码_并查集_二叉排序树_平衡二叉树
本文详细介绍了树与二叉树的应用,涵盖哈夫曼树与哈夫曼编码、并查集以及二叉排序树等内容。首先讲解了哈夫曼树的构造方法及其在数据压缩中的应用;接着介绍了并查集的基本概念、存储结构及优化方法;随后探讨了二叉排序树的定义、查找、插入和删除操作;最后阐述了平衡二叉树的概念及其在保证树平衡状态下的插入和删除操作。通过本文,读者可以全面了解树与二叉树在实际问题中的应用技巧和优化策略。
|
5月前
|
机器学习/深度学习 存储
数据结构学习记录——哈夫曼树(什么是哈夫曼树、哈夫曼树的定义、哈夫曼树的构造、哈夫曼树的特点、哈夫曼编码)
数据结构学习记录——哈夫曼树(什么是哈夫曼树、哈夫曼树的定义、哈夫曼树的构造、哈夫曼树的特点、哈夫曼编码)
125 1
|
存储 算法
数据结构实验十二 哈夫曼树及编码
数据结构实验十二 哈夫曼树及编码
88 0
|
6月前
|
算法 Java
数据结构-构造哈夫曼树【详解+代码+图示】一文解惑!
数据结构-构造哈夫曼树【详解+代码+图示】一文解惑!
2751 0
|
C语言
c语言数据结构-哈夫曼树
c语言数据结构-哈夫曼树
103 0
数据结构——哈夫曼树
哈夫曼树 · 前言 哈夫曼树又叫做最优二叉树,可以将其看作一种特殊的二叉树。 可以说是从堆引入的哈夫曼树;堆的作用是构造最大堆和最小堆实现挑选最值删除的东西,而哈夫曼树也是寻找max和min并对其进行操作。 哈夫曼树的原理:出现频率较高的数占空间小,出现频率较低的数占空间更大。从而实现不压缩数据且节省空间的一种存储方式。
数据结构——哈夫曼树
|
存储 算法
【开卷数据结构 】哈夫曼树
【开卷数据结构 】哈夫曼树
116 0
|
算法
大话数据结构--哈夫曼树及其应用
大话数据结构--哈夫曼树及其应用
124 0
|
C语言
C语言《数据结构》——哈夫曼树
C语言《数据结构》——哈夫曼树
379 0