數據結構課程設計時寫的
// 常量定義
/////////////////////////////
#ifndef G_C //
#define G_C //
#define N 1000 //
#define MAX 99999 //
#endif //
/////////////////////////////
// 統計文件中各個字符時相關結構體
///////////////////////////////////////////////////////////
#ifndef W_C //
#define W_C //
struct Word_Count{ //
char word ; //字符類型 //
int count ; //字符出現次數 //
}; //
struct Word_Count_Array{ //
struct Word_Count wC[N]; //
int point; //定位指針(指向數組wC中第一個空位) //
}; //
#endif //
///////////////////////////////////////////////////////////
// 構建Huffuman樹相關結構體
/////////////////////////////////////////////////////////////
#ifndef H_T //
#define H_T //
struct Node{ //構建哈夫曼樹的節點 //
char word; //
int count; //
struct Node *leftChild,*rightChild; //
int myAdrr,lfAdrr,rgAdrr; //自己|左孩子|右孩子 Adrress //
}; //便於文件中樹的生成 //
struct Node_Array{ //
struct Node node[N]; //
int point; //
}; //
struct Dynamic_Array{ //動態數組 //
int dArray[N]; //
int point; //指向數組中第一個空位 //
}; //
struct WordCode{ //存儲字符以及其編 //
char word; //字符 //
int code[N]; //Huffu編碼 //
int point; //指向數組中第一個空位 //
}; //
struct WordCode_Array{ //存儲字符以及其編碼 //
struct WordCode wCode[N]; //
int point; //指向數組中wCode第一個空位 //
}; //
struct Dynamic_Array dyArr; //輔組存儲編碼的動態數組 //
struct WordCode_Array wCArr; //存儲字符及其編碼 //
int Pos=0; //
#endif //
/////////////////////////////////////////////////////////////
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Function Module : Statistical character frequency *
* *
* Explain : 統計字符頻率(Hz),需要緩衝數組buff. *
* *
* @author: luewang *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include"GlobalVCS.h"
/**
*
* Role: compare word to count
*
* Explain: 將傳入的字符與存儲字符的結構體數組
* 中的字符進行比較,更新字符出現次數
* (Hz)
*
* @return: 無
*
*/
void OperateWC(struct Word_Count_Array* wCA,char word){
int i = 0;
for(; i < wCA->point ; i++){
if(word==wCA->wC[i].word){
wCA->wC[i].count+=1;
break;
}
}
if(i==wCA->point){
wCA->wC[i].word=word;
wCA->wC[i].count=1;
wCA->point=i+1;
}
}
/**
*
* Role: count word
*
* Explain: 統計各個字符出現的頻率(Hz)
*
* @return: 字符頻率結構體數組wCA
*
*/
struct Word_Count_Array SingleChar_Hz(char buff[],int n){
struct Word_Count_Array wCA; //存儲各個字符出現頻數的結構體數組 *
wCA.point=0;
for(int i = 0 ; i < n ; i++){
OperateWC(&wCA,buff[i]);
}
//控制檯打印統計好的字符出現的頻率
printf("+----------+-----------+\n");
printf("+ wCA:字符頻率統計數組 +\n");
printf("+----------+-----------+\n");
printf("| word | count |\n");
printf("+----------+-----------+\n");
for(int i = 0 ; i < wCA.point; i++){
printf("|%10c|%11d|\n",wCA.wC[i].word,wCA.wC[i].count);
printf("+----------+-----------+\n");
}
printf("...Over.....OK...\n\n");
return wCA;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Function Module (core code) : Establishment Of Huffuman Tree. *
* *
* Explain : *
* 使用從文件中統計的字符頻率的結構體數組,循環先序遍歷構建Huffu- *
* -man樹,並另外使用結構體數組統計各個字符哈夫曼編碼。 *
* *
* @author: luewang *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include"GlobalVCS.h"
/**
*
* Role: Sort of Insert
*
* Explain: 利用插入排序將統計好個字符頻率的結構體數組wCA
* 進行升序排序.
*
* @return: 返回後續構建樹所需要的節點的數組
*
*/
struct Node_Array InsertSort(struct Word_Count_Array *wCA){
int i,j;
int tmpCount;
char tmpChar;
for(i = 1 ; i < wCA->point ; i++){
tmpCount = wCA->wC[i].count;
tmpChar = wCA->wC[i].word ;
for(j = i ; j > 0 && wCA->wC[j-1].count > tmpCount ; j--){
wCA->wC[j].count = wCA->wC[j-1].count;
wCA->wC[j].word = wCA->wC[j-1].word ;
}
wCA->wC[j].count = tmpCount;
wCA->wC[j].word = tmpChar ;
}
// printf("\n\n-----------sort----wCA---------------------\n");
// for(int k = 0 ; k < wCA->point; k++){
// printf("wCA : %c---%d \n",wCA->wC[k].word,wCA->wC[k].count);
// }
struct Node_Array nodeArray;
for(int i = 0 ; i < wCA->point ; i++){
nodeArray.node[i].count = wCA->wC[i].count;
nodeArray.node[i].word = wCA->wC[i].word ;
nodeArray.node[i].leftChild = NULL;
nodeArray.node[i].rightChild= NULL;
}
nodeArray.point = wCA->point;
// printf("\n\n-----------sort----nodeArray---------------------\n");
// for(int i = 0 ; i < nodeArray.point ; i++){
// printf("nodeArray : %c----%d \n",nodeArray.node[i].word,nodeArray.node[i].count);
// }
return nodeArray;
}
/**
*
* Role: Sort of the specified interval
* |
* Explain: 利用插入排序指定範圍,將構建哈夫曼樹所需要的結
* 點的數組進行升序排序.(該函數將會被多次調用)
*
* @return: 無
*
*/
void InsertSortSE(struct Node_Array *nA,int start , int end){
if(end - start > 0){
int i,j;
int tmpCount;
char tmpChar;
struct Node *tmpLeft,*tmpRight;
for(i = start + 1 ; i <= end ; i++){
tmpCount = nA->node[i].count;
tmpChar = nA->node[i].word ;
tmpLeft = nA->node[i].leftChild;
tmpRight = nA->node[i].rightChild;
for(j = i ; j > start && nA->node[j-1].count > tmpCount ; j--){
nA->node[j].count = nA->node[j-1].count;
nA->node[j].word = nA->node[j-1].word ;
nA->node[j].leftChild = nA->node[j-1].leftChild;
nA->node[j].rightChild = nA->node[j-1].rightChild;
}
nA->node[j].count = tmpCount;
nA->node[j].word = tmpChar ;
nA->node[j].leftChild = tmpLeft ;
nA->node[j].rightChild= tmpRight;
}
}
}
/**
*
* Role: Copy Array
*
* Explain: 將數組a的指定範圍(start~end)賦值給數組b該範圍
*
* @return: 無
*
*/
void ArrayCopy(int a[],int b[],int start,int end){
if(end >= 0 && start >= 0 && end - start >= 0){
for(int i = start ; i <= end ; i++){
b[i] = a[i];
}
}
}
/**
*
* Role: Traverse
*
* Explain: 利用先序遍歷構建哈夫曼樹(根:Root) 並
* 將遍歷的結果放在全局變量wCArr(保存字
* 符及其編碼的數組)
*
* @return: 無
*
*/
void Traverse(struct Node* Root){
if(Root->leftChild==NULL&&Root->rightChild==NULL){ //已經到了根節點
Root->myAdrr=Pos;//
Root->rgAdrr=0;//
Root->lfAdrr=0;//
Pos+=1;//
wCArr.wCode[wCArr.point].word = Root->word;
ArrayCopy(dyArr.dArray,wCArr.wCode[wCArr.point].code,0,dyArr.point-1);
wCArr.wCode[wCArr.point].point = dyArr.point;
wCArr.point+=1;
dyArr.point-=1;
return;
}
Root->myAdrr=Pos;//
Pos+=1;//
if(Root->leftChild != NULL){
dyArr.dArray[dyArr.point] = 0;
dyArr.point+=1;
Root->lfAdrr=Pos;//
Traverse(Root->leftChild);
}
if(Root->rightChild != NULL){
dyArr.dArray[dyArr.point] = 1;
dyArr.point+=1;
Root->rgAdrr=Pos;//
Traverse(Root->rightChild);
}
dyArr.point-=1;
return ;
}
/**
*
* Role: Traverse
*
* Explain: 純粹先序遍歷樹
*
* @return: 無
*
*/
void TreeT(struct Node* Root){
if(Root->leftChild==NULL&&Root->rightChild==NULL){ //已經到了根節點
printf("|%10c|%11d|\n",Root->word,Root->count);
printf("+----------+-----------+\n");
return ;
}
printf("|%10c|%11d|\n",Root->word,Root->count);
printf("+----------+-----------+\n");
TreeT(Root->leftChild);
TreeT(Root->rightChild);
}
void Traverset(struct Node* Root){
printf("Tree visting is working......\n");
printf("+----------+-----------+\n");
printf("| Visit Tree |\n");
printf("+----------+-----------+\n");
printf("| word | count |\n");
printf("+----------+-----------+\n");
TreeT(Root);
printf("...Over.....OK...\n\n");
}
/**
*
* Role: Make a Huffuman Tree
*
* Explain: 根據存儲字符頻率的結構體數組wCA排序轉化
* 爲創建哈夫曼樹所需要結點數組nodeArray,利
* 用結點數組進行多次排序並且動態增加元素構
* 建哈夫曼樹
*
* @return: Root(Huffuman Tree Root)
*
*/
struct Node* HuffumanTreeBuild(struct Word_Count_Array *wCA){
struct Node_Array nodeArray = InsertSort(wCA);//對統計好的字符頻率結構體數組進行排序並將排序放入nodeArray數組中
printf(">>>Building Huffuman tree is working......\n");
struct Node *Root;
for(int i = 1 ; i < nodeArray.point ; i+=2){
nodeArray.node[nodeArray.point].count = nodeArray.node[i].count + nodeArray.node[i-1].count;
nodeArray.node[nodeArray.point].leftChild = &(nodeArray.node[i-1]);
nodeArray.node[nodeArray.point].rightChild= &(nodeArray.node[i]) ;
nodeArray.node[nodeArray.point].word='~';
Root = &(nodeArray.node[nodeArray.point]);
nodeArray.point +=1;
InsertSortSE(&nodeArray,i+1,nodeArray.point-1);
if(i+1 == nodeArray.point||i+1 == nodeArray.point - 1){
break;
}
}
printf("...Over.....OK...\n\n");
printf("Encoding is working......\n");
Traverse(Root); //遍歷過程中將每個字符類型code編碼存儲存入全局變量wCArr中
printf("...Over.....OK...\n\n");
return Root;
}
/**
*
* Role: Show Huffuman Code
*
* Explain: 顯示(存放在全局變量wCA中的)字符編碼
*
* @return: 無
*
*/
void ShowHuffumanCode(){
printf("+----------+---------------------------+\n");
printf("+ Huffuman Code +\n");
printf("+----------+---------------------------+\n");
printf("| word | code |\n");
printf("+----------+---------------------------+\n");
for(int i = 0 ; i < wCArr.point ; i++){
char str = wCArr.wCode[i].word;
printf("|%-10c|",str);
int j;
for(j = 0 ; j < wCArr.wCode[i].point ; j++){
printf("%d ",wCArr.wCode[i].code[j]);
}
for(int k = 0 ; k < 27-2*j ; k++){
printf(" ");
}
printf("|\n");
printf("+--------------------------------------+\n");
}
printf("...Over.....OK...\n\n");
}
/* * * * * * * * * * * * * * * * * * * * * * * *
* *
* Function Module : < > File Operation *
* *
* Explain : 文件操作模塊 *
* *
* @author: luewang *
* *
* * * * * * * * * * * * * * * * * * * * * * * */
#include"GlobalVCS.h"
/**
*
* Role: read word from src to buff
*
* Explain: 從文件中讀入字符並將其存入buff數組中
*
* @return: buff
*
*/
char* FileInputStream(char* src){
FILE *file;
char buff[MAX];
if((file = fopen(src,"r"))==NULL){
printf("Error : Open File %s is Faile To Open!!! \n",src);
}
printf(">>>Open File directory is : %s \n",src);
int ch , count;
printf("\n-+-+-+-+-+-+-+Content-+-+-+-+-+-+-+-\n"); //顯示從文件中讀出的內容
for(count = 0;(ch=fgetc(file))!=EOF;count++){
buff[count] = ch;
printf("%c",ch);
}
printf("\n-+-+-+-+-+-+-+-End+-+-+-+-+-+-+-+-+-+-\n");
printf("...Over.....OK...\n\n");
fclose(file);
return buff;
}
/**
*
* Role: file visit and save tree
*
* Explain: 先序遍歷保存構建好的哈夫曼樹
*
* @return: 無
*
*/
void SaveTreeVisit(struct Node *Root,FILE *file){
if(Root->leftChild==NULL&&Root->rightChild==NULL){ //葉子節點
printf("|%10c|%11d|%12d|%12d|%12d|\n",Root->word,Root->count,Root->myAdrr
,Root->lfAdrr,Root->rightChild);
printf("+----------+-----------+------------+------------+------------+\n");
fwrite(Root,sizeof(struct Node),1,file);
return;
}
printf("|%10c|%11d|%12d|%12d|%12d|\n",Root->word,Root->count,Root->myAdrr
,Root->lfAdrr,Root->rightChild);
printf("+----------+-----------+------------+------------+------------+\n");
fwrite(Root,sizeof(struct Node),1,file);
SaveTreeVisit(Root->leftChild,file);
SaveTreeVisit(Root->rightChild,file);
}
/**
*
* Role: save huffuman tree to file
*
* Explain: 將根節點是Root的樹保存到dir路徑文件中.
*
* @return : 無
*
*/
void SaveHuffumanTree(char *dir,struct Node *Root){
FILE *file;
if((file = fopen(dir,"wb+")) == NULL){
printf("Error : Save File %s is Faile To Open!!! \n",dir);
}
printf(">>>Save File directory is : %s \n",dir);
printf("+----------+-----------+------------+------------+------------+\n");
printf("| word | count | myAdrr | lfAdrr | rgAdrr |\n");
printf("+----------+-----------+------------+------------+------------+\n");
SaveTreeVisit(Root,file);
printf("...Over.....OK...\n\n");
fclose(file);
}
/**
*
* Role: File Visit And Get Tree
*
* Explain: 從文件中取出哈夫曼樹節點信息放入tmpRoot數組中
* 通過tmpRoot數組中構建哈夫曼樹 , tmpRoot數組每
* 個元素存儲了左右孩子和自己的地址(int)
*
* @return : tmpRoot頭結點(哈夫曼樹根結點)
*
*/
struct Node* GetTreeVisit(FILE *file){
int point = 0;
struct Node tmpRoot[N];
while(fread(&tmpRoot[point],sizeof(struct Node),1,file)!=NULL){
if(tmpRoot[point].lfAdrr==0&&tmpRoot[point].rgAdrr==0){
printf("|%10c|%11d|\n",tmpRoot[point].word,tmpRoot[point].count);
printf("+----------+-----------+\n");
}
point+=1;
}
for(int i = 0 ; i < point ; i++){
if(tmpRoot[i].lfAdrr == 0){
tmpRoot[i].leftChild = NULL;
}else if(tmpRoot[i].lfAdrr != 0){
for(int j = i + 1 ; j < point ; j++){
if(tmpRoot[j].myAdrr == tmpRoot[i].lfAdrr){
tmpRoot[i].leftChild = &tmpRoot[j];
break;
}
}
}
if(tmpRoot[i].rgAdrr == 0){
tmpRoot[i].rightChild = NULL;
}else if(tmpRoot[i].rgAdrr != 0){
for(int j = i + 1 ; j < point ; j++){
if(tmpRoot[j].myAdrr == tmpRoot[i].rgAdrr){
tmpRoot[i].rightChild = &tmpRoot[j];
break;
}
}
}
}
// printf("=-=-=-=-=-=\n");
// for(int i = 0 ; i < point ; i++){
// printf("%c \n",tmpRoot[i].word);
// printf("%d----%d---%d\n",tmpRoot[i].myAdrr,tmpRoot[i].lfAdrr,tmpRoot[i].rgAdrr);
// }
// Traverset(tmpRoot);
return tmpRoot;
}
/**
*
* Role: Get Huffuman Tree
*
* Explain: 從指定(*.dat)文件中獲取獲取哈夫曼樹,給該樹
* 根結點Root賦值 .
*
* @return : 無
*
*/
void GetHuffumanTree(char *dir,struct Node **Root){
FILE *file;
file = fopen(dir,"rb+");
if(file==NULL){
printf("Error : Get File Open is failed To Open : %s\n",dir);
}
printf(">>>Get File directory is : %s \n",dir);
printf("+----------+-----------+\n");
printf("| word | count |\n");
printf("+----------+-----------+\n");
*Root = GetTreeVisit(file); //哈夫曼樹根結點
printf("...Over.....OK...\n\n");
fclose(file);
}
/**
*
* Role: word zip
*
* Explain: 將指定字符ch根據哈夫曼樹編碼(wCArr)進行壓縮至
* 文件 huffuFile 中.
*
* @return : 無
*
*/
void ZIP(int ch,FILE *huffuFile){
for(int i = 0 ; i < wCArr.point ; i++){
if(ch == wCArr.wCode[i].word){
for(int j = 0 ; j < wCArr.wCode[i].point ; j++){
printf("%d",wCArr.wCode[i].code[j]);
fputc(wCArr.wCode[i].code[j]+48,huffuFile);
}
}
}
}
/**
*
* Role: file zip
*
* Explain: 指定文件路徑src進行文件壓縮至一個新的文
* 件中huffuFile
*
* @return : 無
*
*/
void FileZip(char* src){
FILE *file,*huffuFile;
if((file = fopen(src,"r+")) == NULL){
printf("Error : File %s Open is failed!!!\n",src);
}
printf(">>>ZIP File directory is : %s \n",src);
char dir[strlen(src)+5];
strcpy(dir,src);
dir[strlen(dir)-4]='\0';
strcat(dir,"_hf.txt");
// printf("%s\n",dir);
if((huffuFile = fopen(dir,"w+")) == NULL){
printf("Error : Zipped File %s Open is failed!!!\n",dir);
}
printf(">>>Zipped File directory is : %s \n",dir);
int ch;
printf("\n-+-+-+-fake Binary l stream-+-+-+-+-\n");
while((ch=fgetc(file))!=EOF){
ZIP(ch,huffuFile);
}
printf("\n-+-+-+-+-+-+-+-End+-+-+-+-+-+-+-+-+-\n");
printf("...Over.....OK...\n\n");
fclose(file);
fclose(huffuFile);
}
/**
*
* Role: file unzip
*
* Explain: 將指定哈夫曼 0 1 文件(huffuFile)進行哈夫曼樹解
* 碼存入file文件中
*
* @return : 無
*
*/
void UnZIP(struct Node *Root,FILE *huffuFile,FILE *file){
struct Node *root = Root; //哈夫曼樹根結點
int ch;
while((ch=fgetc(huffuFile))!=EOF){
// printf("%c ",ch);
if(ch - 48 == 0){
root=root->leftChild;
}else if(ch - 48 == 1){
root=root->rightChild;
}
if(root->rightChild==NULL&&root->leftChild==NULL){ //已經到了葉節點
fputc(root->word,file);
root=Root; //回到根節點
}
}
}
/**
*
* Role: file unzip
*
* Explain: 對給定文件路徑進行哈夫曼樹解壓 Root:
* 爲哈夫曼樹根結點
*
* @return : 無
*
*/
void FileUnZip(char* dir,struct Node *Root){
//printf("File UnZip\n");
//Traverset(Root);
FILE *file,*huffuFile;
if((huffuFile = fopen(dir,"r+")) == NULL){
printf("Unzip File Open is failed : %s\n",dir);
}
printf(">>>Unzip File directory is : %s \n",dir);
char Dir[strlen(dir)];
strcpy(Dir,dir);
Dir[strlen(dir)-7]='\0';
strcat(Dir,"`.txt");
//printf("%s\n",Dir);
if((file= fopen(Dir,"w+")) == NULL){
printf("Unzipped File Open is failed : %s\n",Dir);
}
printf(">>>Unzipped File directory is : %s \n",Dir);
UnZIP(Root,huffuFile,file);
printf("...Over.....OK...\n\n");
fclose(file);
fclose(huffuFile);
}