(注:
本代码是使用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"); }
运行结果截图如下: