哈夫曼編碼壓縮,解壓,壓縮比,編碼表,儲存到檔案
阿新 • • 發佈:2019-01-27
//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++; } */
請尊重過別人的知識,如果轉載請註明地址
另外: 如果有錯誤或者需要修改的地方,歡迎大家指出