
哈夫曼编码、译码处理文件
发布日期:2021-05-06 06:51:33
浏览次数:31
分类:精选文章
本文共 4075 字,大约阅读时间需要 13 分钟。
课程考核写的代码构造Huffman编码,贴出来留个纪念。
编码基本思想如下:
1)将哈夫曼树向量ht中的2n-1个结点进行初始化;
2)将n个 结点的权值存入向量ht的前n个分量中;
3)对n个结点进行n-1次合并,将生成的n-1个新结点依次存入向量ht的第t(n+1≤t≤2n-1)个分量中。
译码:
我所采取的译码方法不是通过读取哈夫曼树的数据,而是利用哈夫曼编辑好的密文构成一定规律的数组,在和哈夫曼编码进行比对,从而获得原码。
文件处理:
在本次实验中设计到了有关文件的处理,由于每次编码和译码都需要将之前的编码完成以及译码完成的文件进行清空处理,所以在进行文件处理时所使用的命令是“w+”,对原文件进行清理再进行二次写入。
#include#include #define MAX 10000#define MAXLEN 10000//定义哈夫曼树的存储结构typedef struct{ char data; int weight; int parent; int lch; int rch;}HuffNode;//定义哈夫曼编码的储存结构typedef struct{ char bit[MAX]; int start;}HuffCode;HuffNode ht[2 * MAX];HuffCode hcd[MAX];int n, w, z, zz[MAX] = {0}; //n为节点的数量,w为总字符的数目char a1[100000];char a2[100000];//sum函数的相关数据的初始化int x[29] = { 0 };char y[29];int a[29] = { 0 };char b[29];int num; //哈夫曼编码之后的字符数char code[MAX] = { " " }; //译码之后的字符//读取文件int view(char *codefile){ int n,num = 0; FILE* file1 = fopen(codefile, "r"); if (file1 == NULL) printf("打开文件失败!!!\n"); for (int i = 0; ; i++) { { fscanf(file1, "%c", &a1[i]); if (a1[i] == '#') return 0; printf("%c", a1[i]); } } fclose(file1);}//编码所使用的读取文件int read_file1(char *codefile){ int num = 0; FILE* file1 = fopen(codefile, "r"); if (file1 == NULL) printf("打开文件失败!!!\n"); for (int i = 0; ; ++i) { { fscanf(file1, "%c", &a1[i]); if (a1[i] == '#') return 0; } } fclose(file1); return 0;}//译码所使用的读取文件int read_file2(char *codefile){ num = 0; FILE* file2 = fopen(codefile, "r"); if (file2 == NULL) { printf("文件为空!"); return 0; } for (int i = 0; ; ++i) { fscanf(file2, "%c", &a2[i]); if (a2[i] == NULL) break; // printf("%c", a2[i]); //测试用 num++; } printf("\n"); //测试用 fclose(file2); return 0;}//保存编码文件int save_file1(){ FILE * file; int k,t,i; file = fopen("Encode.txt", "w+"); //原本使用的 r+命令会造成字符的叠加,使用w+即可清除原文件,重新写入 if ((file = fopen("Encode.txt", "w+")) == NULL) { printf("文件打开失败!"); exit(0); }//对编码成功后的数据进行元数据比对,对原数据进行编码 printf("检验字符数:%d\n", w); //检验使用 for (t = 0; t < w; t++) { z = 0; for (i = 1; i <= n; i++) { if (a1[t] == ht[i].data) { //测试用 //printf("%c:", ht[i].data); for (k = hcd[i].start + 1; k <= n; k++) { //printf("%c", hcd[i].bit[k]); fprintf(file, "%c", hcd[i].bit[k]); z++; } //printf("\n"); // for (k = hcd[i].start+1; k<=n; k++) } } zz[t+1] = z; //此处的值用于译码使用 // printf("%d-", z); } fclose(file); printf("编码成功!\n"); return 0;}//保存解码文件 5.2更改保存的方式 使用fprintfint save_file2(int t){ FILE * file; file = fopen("Decode.txt", "w+"); if ((file = fopen("Decode.txt", "w+")) == NULL) { printf("文件打开失败!"); exit(0); } for (int i = 0; i < t; i++) //该w为t,t为实际的译码数 { fprintf(file, "%c",code[i]); } fclose(file); printf("译码成功!\n"); return 0;}//数据节点的统计void sum(){ int i=0,k=1,t=0;// printf("1"); //测试用 while (a1[i] != '#') { switch (a1[i]) { case 'a':x[0]++; break; case 'b':x[1]++; break; case 'c':x[2]++; break; case 'd':x[3]++; break; case 'e':x[4]++; break; case 'f':x[5]++; break; case 'g':x[6]++; break; case 'h':x[7]++; break; case 'i':x[8]++; break; case 'j':x[9]++; break; case 'k':x[10]++; break; case 'l':x[11]++; break; case 'm':x[12]++; break; case 'n':x[13]++; break; case 'o':x[14]++; break; case 'p':x[15]++; break; case 'q':x[16]++; break; case 'r':x[17]++; break; case 's':x[18]++; break; case 't':x[19]++; break; case 'u':x[20]++; break; case 'v':x[21]++; break; case 'w':x[22]++; break; case 'x':x[23]++; break; case 'y':x[24]++; break; case 'z':x[25]++; break; case ',':x[26]++; break; case '.':x[27]++; break; case ' ':x[28]++; break; } w++; i++; } //节点数据的赋值 for (i = 0; i < 27; i++) { y[i] = 'a' + i; // printf("%c", y[i]); //测试用 } y[26] = ','; y[27] = '.'; y[28] = ' '; //节点的计算 for (i = 0; i < 29; i++) { if (x[i] == 0) t++; //计算无数据节点 } n = 29 - t; printf("节点数n:%d 字符总数w:%d\n", n,w); }//权值以及相关节点数据的赋值void sum2(){ int i,k=0; for (i = 0; i < 29; i++) { if (x[i] != 0) { a[k] = x[i]; b[k] = y[i]; k = k + 1; //妥妥的 } } //数组给结构体权值数组赋值 5.2修改了i的初始值,以及循环的条件 for (i = 1, k = 0; i <= n, k
结果如下列图片所示:
源文件:
编码文件:
译码文件: