//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
#include
#include
/*
#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++;
}
*/
请尊重过别人的知识,如果转载请注明地址
另外: 如果有错误或者需要修改的地方,欢迎大家指出