//mian.c
#include "FunctionReference.h" int main() { HuffmanTree HT; //哈夫曼树 int sum; //统计的字符总数 int n; //字符的种数 int remainBit; //最后一个字节中剩下的没有意义的位数 int charCiphertextLength; //密文数组的字节数(大小) double yasuobi; //压缩比 int choose = 1; Char *bianma; //统计字符编码表 char *charAll ; //所有的字符 unsigned char *yima; //压缩后字符的存放位置 char *decodeString = (char *)malloc(sizeof(char) * 400);//译码后存放字符的数组 //初始化编码表 if(!InitChar(&bianma)) return 0; while(choose <= 8 && choose >= 1) { menu (); printf("请输入您的选择: "); scanf("%d", &choose); Choose(choose); switch(choose) { case 1: InputSourceInConsole(&charAll); //输入字符 sum = Sum(charAll, &bianma, &n);//统计字符 HuffmanCoding(&HT, n, &bianma); //进行哈夫曼编码 yima = Compress(charAll, n, HT, &remainBit, &charCiphertextLength); //此处译出来的是密文数组 printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); system("pause"); break; case 2: ReadCharInSourceFile(&charAll); //读取文件字符 sum = Sum(charAll, &bianma, &n);//统计字符 HuffmanCoding(&HT, n, &bianma); //进行哈夫曼编码 yima = Compress(charAll, n, HT, &remainBit, &charCiphertextLength); //此处译出来的是密文数组 printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); system("pause"); break; case 3: ReadHTInHTCODE_txtFile(&HT, &remainBit, &n); //读取HTCODE.txt文件 ReadCiphertextInDataSave_txt(&charCiphertextLength, &yima); //读取DataSave.txt文件 printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); system("pause"); break; case 4: WriteCompressData(HT, remainBit, charCiphertextLength, yima, n);//两个文件都写好了 printf("\n 已经成功保存! \n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); system("pause"); break; case 5: printf("\n"); InformationFileDecoding(HT, yima, decodeString, n, charCiphertextLength, remainBit);//进行译码解码 OutputTranslateSource(decodeString); //输出原字符 printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); system("pause"); break; case 6: yasuobi = (double)charCiphertextLength / sum; printf( "压缩比为 : %.2lf%% \n", yasuobi * 100); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); system("pause"); break; case 7: printf("\n"); print(n, HT); //打印编码表 printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); system("pause"); break; case 8: charCiphertextLength = 0.0; free(HT); // free(yima); free(bianma); free(charAll); if(!InitChar(&bianma)) return 0; printf("\n已清空所有分配的空间并重新完成了编码的初始化!可以继续测试新的数据!\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); system("pause"); break; default : exit(0); } } return 0; } /*说明 需要储存的东西 压缩时: 1.随便储存很多待压缩的字符 2.编码表(来统计字符并来建立哈夫曼数) 3.建立哈夫曼数,通过编码表和字符 4.压缩后的数组 解压: 1.哈夫曼树 HT 2.剩余的位数remainBit //HT和remainBit存放在一个文件中,可以先读取remainBit(四个字节),然后全部是HT的提取,每取一次就计算器加1,就可以得到n 3.字符的种数 n 4.压缩后的字符数组yima 已解决 5.解压放置的数组 decodingString 已解决,分配1000个 6.压缩后多少个存储字符charCipherTextLength 已解决 */
//FunctionReference.h
#ifndef HAFFUMANCODE_C //如果没有定义过此宏,就定义 #define HAFFUMANCODE_C #include <stdio.h> #include <stdlib.h> #include <string.h> /* #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define OVERFLOW -2 */ //如果用此头文件的地方要用到这些宏,那么就业可以再此申明这些宏,在用的文件1,与用文件1的文件只能有一次定义 typedef int Status; typedef struct { char code[10]; //编码 char node; //字符 unsigned int weight; //权重 unsigned int parent, lchild, rchild; //父结点,左右孩子 } HTNode, *HuffmanTree; //动态分配数组储存哈夫曼树 typedef struct Char { char code[10]; //压缩编码 char node; //存放字符 int weight; //权重 struct Char *next; }Char; //建立统计字符的编码表头节点 Status InitChar (Char **bianma); //统计字符种数,和编码表 int Sum(char zifu[], Char **bianma, int *n); //打印编码表 void print(int n, HuffmanTree HT); //每次选择其中最小的两个数 void Select(HuffmanTree HT, int maxBorder, int *minL, int *minR); //--------哈夫曼树和哈夫曼编码的储存表示--------------- int HuffmanCoding(HuffmanTree *HT, int n, Char **bianma); //压缩(根据输入字符进行压缩,结果返回压缩后的密文数组) unsigned char* Compress(char *charAll, int charTypeNumber, HuffmanTree HT, int *remainBit, int *saveFileArrayLength); //译码(按压缩后的数组方式进行译码) int InformationFileDecoding(HuffmanTree HT, unsigned char fileCharArr[], char decodeString[], int charTypeNumber, int charLength, int remainBit); //读取HTCODE.txt文件(树HT和remianBit和节点数n) Status ReadHTInHTCODE_txtFile(HuffmanTree *HT, int *remainBit, int *n); //读取密文数据dataSave.txt(读取到的是经过压缩,并且以8位一个字符储存的压缩数组) Status ReadCiphertextInDataSave_txt(int *charCiphertextLength, unsigned char **yima); //保存树和密文数组,还有最后一字节剩下位数 Status WriteCompressData(HuffmanTree HT, int remainBit, int charCiphertextLength, unsigned char *yima, int n); //从源文件读入字符 Status ReadCharInSourceFile(char **charAll); //经过翻译后,输出原文字符 Status OutputTranslateSource(char *decodeString); //从控制台输入字符 Status InputSourceInConsole(char **charAll); //选择显示 void Choose(int choose); //菜单显示 void menu (); #endif
//FunctionReference.c
#include "FunctionReference.h" #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define OVERFLOW -2 //建立统计字符的编码表头节点 Status InitChar (Char **bianma) { Char *head; head = (Char *)malloc(sizeof(Char) * 1); head->next = NULL; *bianma = head; return OK; } //统计字符种数,和编码表 int Sum(char zifu[], Char **bianma, int *n) { int i = 0; //字符数组下标 int j = 1; //字符种数 int sum = 0; //字符个数 Char *p = *bianma ; Char *z = *bianma ; //p 的前驱 while (zifu[i]) { sum++; p = *bianma; while (p) { z = p; if (p->node == zifu[i]) //找到此字符,就把对应字符的权重加1,并跳出 { p->weight++; break; } p = p->next; } if (!p) //没有找到字符,则添加一种新的字符 { p = (Char *)malloc(sizeof(Char)*1); p->node = zifu[i]; p->weight=1; p->next = NULL; z->next = p; j++; } i++; } *n=(j-1); return sum; } //打印编码表 void print(int n, HuffmanTree HT) { int i; for (i = 1; i <= n; i++) { printf("第 %2d个字符是: %c ,其编码是 %-8s: ,其权重是 : %3d \n", i, HT[i].node, HT[i].code, HT[i].weight); } } //每次选择其中最小的两个数 void Select(HuffmanTree HT, int maxBorder, int *minL, int *minR) { int i, j; unsigned int minLastOneW, minLastTwoW; i = 1; //找第一个parent不为0的位置,为最小默认值 while (i <= maxBorder) { if (HT[i].parent == 0) { minLastOneW = HT[i].weight; *minL = i; break; } i++; } //找出最小位置 for (i = 1; i <= maxBorder; i++) { if ((HT[i].weight < minLastOneW) && (HT[i].parent == 0)) { *minL = i; minLastOneW = HT[i].weight; //找到要更新 } } j = 1; //保证第二个最小数不和第一个最小数的位置重合且其parent不为0的位置,为第二小的默认值 while(j <= maxBorder) { if ((j != *minL) && (HT[j].parent == 0)) { minLastTwoW = HT[j].weight; *minR = j; break; } j++; } //找出第二小位置 for (j = 1; j <= maxBorder; j++) { if((HT[j].weight < minLastTwoW) && (HT[j].parent == 0) && (j != *minL)) { *minR = j; minLastTwoW = HT[j].weight; } } } //--------哈夫曼树和哈夫曼编码的储存表示--------------- int HuffmanCoding(HuffmanTree *HT, int n, Char **bianma) { Char *q = (*bianma)->next; //字符统计编码表循环变量 HuffmanTree p; //遍历循环变量 int s1 = 1, s2 = 2; //每次权重最小的两个数的位置 int start; //求编码的开始位置 int codeC, codeF; //编码变量 char *cd; //储存每段编码的字符 int m; //总节点数 int i; //循环变量 if (n <= 1) return ERROR; m = 2 * n - 1; *HT = (HuffmanTree)malloc((m + 1)*sizeof(HTNode)); p = *HT + 1; //初始化前n个叶子节点p = *(HT + 1) for (i = 1; i <= n; ++i, ++p) { p->weight = q->weight; q = q->next; //赋值一位,就要往后移一位 p->lchild = p->rchild = p->parent = 0; } //初始化后面m-1个分支 for (; i <= m; ++i, ++p) { p->weight = 0; p->lchild = p->rchild = p->parent = 0; } //建立哈夫曼树 for (i = n + 1; i <= m; ++i) { Select(*HT, (i - 1), &s1, &s2); (*HT)[s1].parent = i; (*HT)[s2].parent = i; //把每次找到的两个最小下标的父节点置为i (*HT)[i].lchild = s1; (*HT)[i].rchild = s2; //把当前位置的两个孩子分别置为最小的下标 (*HT)[i].weight = (*HT)[s1].weight + (*HT)[s2].weight ; } //叶子到根逆向求每个字符的哈夫曼编码 cd = (char *)malloc(n * sizeof(char)); //每种编码的存放,不超过n个,因为树的深度不会超过n q = (*bianma)->next ; cd[n - 1] = ‘\0‘; for (i = 1; i <= n; i++) { start = n - 1; codeC = i; codeF = (*HT)[i].parent; //求每一个节点的编码 while (codeF != 0) { if ((*HT)[codeF].lchild == codeC) cd[--start] = ‘0‘; else cd[--start] = ‘1‘; codeC = codeF; codeF = (*HT)[codeF].parent; } strcpy((*HT)[i].code, &cd[start]); (*HT)[i].code[n-start] = ‘\0‘; } free(cd); //把字符统计编码表中的值复制到HT表中 q = (*bianma)->next; //首元结点开始 for(i = 1; i <= n; i++) { (*HT)[i].node = q->node; q = q->next; } return OK; } //压缩(根据输入字符进行压缩,结果返回压缩后的密文数组) unsigned char* Compress(char *charAll, int charTypeNumber, HuffmanTree HT, int *remainBit, int *saveFileArrayLength) { int k = 0; //每个字符对应的每个编码的下表控制 int i = 0; //每个字符的下标控制 int j = 1; //每种字符对应去查表的下标控制 int array = 0; //存放8位0/1的字符变量 int count = 0; //计数器,统计0/1总的个数 unsigned char *comArrays = (char *)malloc(sizeof(char) * 1);//先分配一个空间 //错误检测 if (charTypeNumber <= 1) return ERROR; printf("压缩后的0/1密文: \n"); comArrays[0] = ‘0‘; while (charAll[i]) { for (j = 1; j <= charTypeNumber; j++) { if (charAll[i] == HT[j].node) { printf("%s", HT[j].code); //直接打印压缩码 //用动态数组来存 k = 0; while(HT[j].code[k]) { comArrays[array] = comArrays[array] | (HT[j].code[k] - ‘0‘); count++; //移一位就计数器加一 if(count%8 == 0) { comArrays = ( unsigned char *)realloc(comArrays, sizeof(char) * (count/8 + 1)); //满了一个就在分配一个 array++; //数组储存的下标变量 comArrays[array] = 0; //每循环一次,就要把新的初值归0 } comArrays[array] = comArrays[array] << 1; //求一位,则往左移一位 k++; } } } i++; } printf("\n"); *remainBit = 8 - (count % 8); //记录下未在最后一个字符中占位置的剩下的0/1个数 if((count%8) != 0)//此处如果移动的次数不是8的整数,则肯定上面有几位没有移动的,所以要在手动左移完剩下的次数 { comArrays[array] = comArrays[array] << (*remainBit - 1); } comArrays[array + 1] = ‘\0‘; //给压缩的数组加一个结束符 *saveFileArrayLength = array + 1; //保留存储数组的长度 return comArrays; } //译码(按压缩后的数组方式进行译码) int InformationFileDecoding(HuffmanTree HT, unsigned char fileCharArr[], char decodeString[], int charTypeNumber, int charLength, int remainBit) { //fileCharArr[]表示从文件中读取的全部字符(此表示的是0/1,decodeString[]表示译出来的字符储存数组,charTypeNumber为节点个数,即字符种树),posotionInHT表示每次在表中的位置状态 int i = 0; //每个字符换成8位0/1位置控制变量 int k = 0; //传的字符位置的下标控制 int j = 0; //把译出来的字符存放到数组的下标控制,并且保持每次运行的位置不变 unsigned char comString[8]; //每一次8位的0/1的存放地方 unsigned char moveBitCompare; //移位控制变量 int positionInHT = 2 * charTypeNumber - 1; //查找哈夫曼表的下标控制,当每次译出来一个字符的时候,就把其置换为2*n-1 int breakFlag = 0; //错误检测 if (charTypeNumber <= 1) return ERROR; for(k = 0; k < charLength && breakFlag == 0; k++) { //把两个字符,转换成8位0/1,并存放在comString数组中 moveBitCompare = 1 << 7; for(i = 0; i <= 7; i++) { comString[i] = ((fileCharArr[k] & moveBitCompare) >> (7 - i)); moveBitCompare = moveBitCompare >> 1; } //进行8位字符的译码,并把译出来的字符放在decodeString数组中 for(i = 0; i < 8; i++) { if ((comString[i] & 1) == 0) positionInHT = HT[positionInHT].lchild; else positionInHT = HT[positionInHT].rchild; if (HT[positionInHT].lchild == 0 || HT[positionInHT].rchild == 0) { decodeString[j] = HT[positionInHT].node; j++; if(((k == (charLength - 1)) && (i == (8 - remainBit - 1))) || (k == (charLength - 2) && (remainBit == 8) && i == 7) ) { breakFlag = 1; //如果剩余的数为8位,即多分配了一个字节则,要此处判断直接跳出,而不用再计算最后一个全为0且不用计算的了 break; //如果译出了最后一个字符,就结束(k指示到了最后一个字符,且i是最后一个有意义的0/1) } positionInHT = 2 * charTypeNumber - 1; //每找出一个字符就重新冲根节点开始找 } } } decodeString[j] = ‘\0‘; //给字符加结束符 return j; //返回译出来的字符个数 } //读取HTCODE.txt文件(树HT和remianBit和节点数n) Status ReadHTInHTCODE_txtFile(HuffmanTree *HT, int *remainBit, int *n) { int m; int end; FILE *fp; if ((fp = fopen("HTCODE.txt", "rb")) == NULL) { printf( "打开文件失败!\n"); exit(0); } else { if(fp)//打开文件求字节长度 { fseek(fp, 0L, SEEK_END); end = ftell(fp); fclose(fp);//此处关闭 } m = (end - 4)/sizeof(HTNode); //m表示树中的全部节点 *n = (m + 1)/2; //n表示树中叶子节点数, 得到字符种类n printf(" 节点种数 : %d \n", *n); printf(" 节点总数 : %d \n", m); *HT = (HuffmanTree)malloc((m + 1)*sizeof(HTNode));//分配树的全部节点空间 fp = fopen("HTCODE.txt", "rb"); fread(remainBit, sizeof(int), 1, fp); //读出剩余位数,得到remainBit //printf(" remainBitjj : %d \n", remainBit); fread(*HT + 1, sizeof(HTNode), m, fp); //读取了整棵树,并且下标从1开始 } fclose(fp); return OK; } //读取密文数据dataSave.txt(读取到的是经过压缩,并且以8位一个字符储存的压缩数组) Status ReadCiphertextInDataSave_txt(int *charCiphertextLength, unsigned char **yima) { int end; //字节长度 FILE *fp; fp = fopen("DataSave.txt", "rb"); if(fp) { fseek(fp, 0L, SEEK_END); end = ftell(fp); fclose(fp); } printf(" 文件中字符个数 : %ld \n", end); *charCiphertextLength = end; //得到密文数组的长度charCiphertextLength *yima = (unsigned char *)malloc( sizeof(char) * end); //分配密文长度大小的字符长度 if ((fp = fopen("DataSave.txt", "rb")) == NULL) { printf( "打开文件失败!\n"); exit(0); } else { fread(*yima, 1, *charCiphertextLength, fp); //从文件中得到密文数组yima } fclose(fp); return OK; } //保存树和密文数组,还有最后一字节剩下位数 Status WriteCompressData(HuffmanTree HT, int remainBit, int charCiphertextLength, unsigned char *yima, int n) { FILE *fp; //树HT和剩余位数remainBit储存HTCODE.txt文件中 if ((fp = fopen("HTCODE.txt", "wb")) == NULL) { printf( "打开文件失败!\n"); exit(0); } else { fwrite(&remainBit, sizeof(int), 1, fp); //写一个最后剩余位数到文件中 //printf(" remainBit: %d \n", remainBit); fwrite(HT+1, sizeof(HTNode), (2 * n), fp); //把整棵树写入文件,下标从1开始 } fclose(fp); //密文数组存储到dataSave.txt文件中去 if ((fp = fopen("dataSave.txt", "wb")) == NULL) { printf( "打开文件失败!\n"); exit(0); } else { fwrite(yima, 1, charCiphertextLength, fp); } fclose(fp); return OK; } //从源文件读入字符 Status ReadCharInSourceFile(char **charAll) { int end; FILE *fp; //从文件SourceFile.txt中读入字符 fp = fopen("SourceFile.txt", "rb"); if(fp) { fseek(fp, 0L, SEEK_END); end = ftell(fp); fclose(fp); } printf(" 文件中字符个数 : %ld \n", end); *charAll = (char *)malloc( sizeof(char) * (end+1)); //分配文件在文件大小个可用字符 if ((fp = fopen("SourceFile.txt", "rb")) == NULL) { printf( "打开文件失败!\n"); exit(0); } else { fread(*charAll, 1, end, fp); (*charAll)[end] = ‘\0‘; } fclose(fp); return OK; } //经过翻译后,输出原文字符 Status OutputTranslateSource(char *decodeString) { int i = 0; while(decodeString[i]) { printf("%c ", decodeString[i]); i++; } printf("\n"); return OK; } //从控制台输入字符 Status InputSourceInConsole(char **charAll) { *charAll = (char *)malloc(sizeof(char)*400); printf("请输入一段英文字符: \n"); fflush(stdin); gets(*charAll); return OK; } //选择显示 void Choose(int choose) { switch(choose) { case 1: system("cls"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf(" 您选择了 1 -- 从键盘输入字符进行压缩 \n"); break; case 2: system("cls"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf(" 您选择了 2 -- 从文件读取字符进行压缩 \n"); break; case 3: system("cls"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf(" 您选择了 3 -- 从文件读取密文进行解码 \n"); break; case 4: system("cls"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf(" 您选择了 4 -- 保存压缩及树文件 \n"); break; case 5: system("cls"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf(" 您选择了 5 -- 根据译码测试输出源码 \n"); break; case 6: system("cls"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf(" 您选择了 6 -- 计算压缩比 \n"); break; case 7: system("cls"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf(" 您选择了 7 -- 打印编码表 \n"); break; case 8: system("cls"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf(" 您选择了 8 -- 清空表 \n"); break; default : { printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf(" 您选择了其他 -- 退出程序 , 程序即将退出! \n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); } } } //菜单显示 void menu () { system("cls"); printf("┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n"); printf("┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫\n"); printf("┃ ┃\n"); printf("┃ 欢 迎 使 用 哈 夫 曼 压 缩 软 件 ┃\n"); printf("┃ ┃\n"); printf("┃ 主 菜 单 ┃\n"); printf("┃ ┃\n"); printf("┃ ( 请按提示操作 ) ┃\n"); printf("┃ ┃\n"); printf("┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫\n"); printf("┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫\n"); printf("┃ ┃\n"); printf("┃ 操 作 : ┃\n"); printf("┃ 1 从键盘输入字符进行压缩 ┃\n"); printf("┃ ┃\n"); printf("┃ 2 从文件读取字符进行压缩 ┃\n"); printf("┃ ┃\n"); printf("┃ 3 从文件读取密文进行解码 ┃\n"); printf("┃ ┃\n"); printf("┃ 4 保存压缩及树文件 ┃\n"); printf("┃ ┃\n"); printf("┃ 5 根据译码测试输出源码 ┃\n"); printf("┃ ┃\n"); printf("┃ 6 计算压缩比 ┃\n"); printf("┃ ┃\n"); printf("┃ 7 打印编码表 ┃\n"); printf("┃ ┃\n"); printf("┃ 8 清空表 (其他键退出) ┃\n"); printf("┃ ┃\n"); printf("┃ ┃\n"); printf("┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫\n"); printf("┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n"); } /* //另外一种译码方式 int InformationFiveDecoding(HuffmanTree HT, int n, int temp, unsigned char fileCharArr[], char decodeString[]) { //fileCharArr[]表示每次从文件中读取两个字符(此表示存了16位0/1,decodeString[]表示译出来的字符储存数组,n为节点个数,即字符种树),temp表示每次在表中的位置状态 int i = 0; //二个字符换成16位0/1位置控制变量 int k = 0; //传的两个字符的下标控制 static int j = 0; //把译出来的字符存放到数组的下标控制,并且保持每次运行的位置不变 char comString[17]; //每一次16位的0/1的存放地方 //错误检测 if (n <= 1) return ERROR; //把两个字符,转换成16位0/1,并存放在comString数组中 for(k = 1, i = 15; i >= 0; i--) { comString[i] = (fileCharArr[k]&1); fileCharArr[k] = fileCharArr[k] >> 1; if(i%8 == 0) k--; }printf("\n"); //测试0/1的译码是否正确 for(i = 0; i < 16; i++) { printf("%d | ", comString[i]); } //测试 //进行16位字符的译码,并把译出来的字符放在decodeString数组中 for(i = 0; i < 16; i++) { if ((comString[i]&1) == 0) temp = HT[temp].lchild; else temp = HT[temp].rchild; if(HT[temp].lchild == 0 || HT[temp].rchild == 0) { decodeString[j] = HT[temp].node; j++; temp = 2 * n - 1; } } //测试是否每次能翻译出来 for(i = 0; i < j; i++) { printf("%c ", decodeString[i]); } printf("\n"); return temp; //通过返回上一次的状态值来为下一次的开始赋初位置 } //main中 temp = 2 * n - 1; i = 0; while(yima[i]) { fileCharArr[0] = yima[i]; fileCharArr[1] = yima[++i]; temp = InformationFiveDecoding(HT, n, temp, fileCharArr, decodeString); i++; } */
请尊重过别人的知识,如果转载请注明地址
另外: 如果有错误或者需要修改的地方,欢迎大家指出
哈夫曼编码压缩,解压,压缩比,编码表,储存到文件,布布扣,bubuko.com
原文:http://blog.csdn.net/cs_polebear/article/details/21109391