//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++;
}
*/
請尊重過別人的知識,如果轉載請註明地址
另外: 如果有錯誤或者需要修改的地方,歡迎大家指出