ハフマンツリーのファイル圧縮と解凍

データ構造コースの設計中に書かれました

#include<windows.h>

//使用时间时调用  

/
#ifndef T_MS               //
#define T_MS               //
DWORD start,stop;          //
#endif			   //
/
              
//  常量定义 
 
/
#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"



#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 ;
   }
   
	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;

	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,int *count,int *max){
	if(Root->leftChild==NULL&&Root->rightChild==NULL){  //已经到了根节点 
		printf("|%10c|%11d|\n",Root->word,Root->count);	
		printf("+----------+-----------+\n");	
		
		if(*max < *count){
			*max = *count;
		}
		
		(*count)--;
		return ;
	}
	
	printf("|%10c|%11d|\n",Root->word,Root->count);	
	printf("+----------+-----------+\n");		
	
	if(Root->leftChild){
		(*count)++;
		TreeT(Root->leftChild,count,max);
	}
	
	if(Root->rightChild){
		(*count)++;
		TreeT(Root->rightChild,count,max);
	}
	
	(*count)--;
	return ;
}
 
int Traverset(struct Node* Root){
	//开始时间 
	start =GetTickCount();    
	
	printf("Tree visting is working......\n");
	
	printf("+----------+-----------+\n");
	printf("|   Visit     Tree     |\n");
	printf("+----------+-----------+\n");
	printf("|   word   |   count   |\n");
	printf("+----------+-----------+\n");
	
	if(Root==NULL){
		return 0;
	}
	
	int count=1;
	int max = 0;
	
	TreeT(Root,&count,&max);
	
	//结束时间 
	stop =GetTickCount();	
	printf("...Over.....OK...(%lld ms)\n\n",stop-start);
	
	return max; 
}

 

/**
 *
 * Role:    Make a Huffuman Tree
 *		                                                
 * Explain: 根据存储字符频率的结构体数组wCA排序转化
 *			为创建哈夫曼树所需要结点数组nodeArray,利
 *			用结点数组进行多次排序并且动态增加元素构
 *			建哈夫曼树 
 *
 * @return: Root(Huffuman Tree Root) 
 *
 */
struct Node* HuffumanTreeBuild(struct Word_Count_Array *wCA){
	//开始时间 
	start =GetTickCount();    
	
	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;
		}
	}
	
	//结束时间 
	stop =GetTickCount();	
	printf("...Over.....OK...(%lld ms)\n\n",stop-start);
	
	//开始时间 
	start =GetTickCount(); 
	
	printf("Encoding is working......\n");
	
	Traverse(Root);        //遍历过程中将每个字符类型code编码存储存入全局变量wCArr中 
	
	//结束时间 
	stop =GetTickCount();	
	printf("...Over.....OK...(%lld ms)\n\n",stop-start);
	
	return Root;
}




/**
 *
 * Role:    Show Huffuman Code 
 *
 * Explain: 显示(存放在全局变量wCA中的)字符编码
 *		 
 * @return: 无
 * 
 */
void ShowHuffumanCode(){
	//开始时间 
	start =GetTickCount(); 
	
	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");
		
	}
	
	//结束时间 
	stop =GetTickCount();	
	printf("...Over.....OK...(%lld ms)\n\n",stop-start);
	
}




//辅组二叉树格式二维数组形成 (树枝高度)
int F(int x){
	if(x == 1){
		return 1;
	}else if(x == 2){
		return 2;
	}
	if(x >= 3){
		return 2*F(x-1) + 1;
	} 
	return -1;
}
//辅组二叉树格式二维数组形成 
int HelpFunc(int x,int base1,int base2,int spare){
	if(x == 2){
		return base1;
	}else if(x == 3){
		return base2;
	}
	if(x > 3){
		return 2*HelpFunc(x-1,base1,base2,spare) + spare;
	}
	return -1;
}
/**
 *
 * Role:    Draw binary tree in console
 *		
 * Explain: 绘制二叉树在控制台
 *
 * @return: void
 
 *
 */
void PaintBiTree(struct Node* Root){
	//开始时间 
	start =GetTickCount();    
	
	int deep = Traverset(Root);       //树的深度
	int branch;                       //枝长        
	int baseW = HelpFunc(deep,4,11,1);//数组宽度{ f(2) = 4 f(3) = 11 f(n) = 2*f(n-1) + 1 (n>=2) }
	int deepH = HelpFunc(deep,3,6,0); //数组高度{ f(2) = 3 f(3) = 6  f(n) = 2*f(n-1) (n>=2)     }
	
	//printf("deepH = %d baseW = %d\n",deepH,baseW);
	
	struct Node *treeDim[deepH][baseW],*tmpL,*tmpR;
	
	tmpL =(struct Node*)malloc(sizeof(struct Node));
	tmpR =(struct Node*)malloc(sizeof(struct Node));
	tmpL->word='\\';
	tmpR->word='\/';

	for(int i = 0 ; i < deepH ; i++){
		for(int j = 0 ; j < baseW ; j++){
			treeDim[i][j]=NULL;
		}
	}
	
	treeDim[0][baseW/2] = Root;
	 
	
	//二叉树格式创建 
	int floor;
	for(int i = 0,floor = 1 ; floor <= deep; floor++,i+=branch+1){
		for(int j = 0 ; j < baseW  ;j++){
			if(treeDim[i][j]!=NULL){
				if(treeDim[i][j]->leftChild!=NULL){   //左孩子
					branch = F(deep - floor ); 
					for(int k = 1 ; k <= branch ; k++){
						treeDim[i+k][j-k] = tmpL;
					}
					treeDim[i+branch+1][j-branch-1] = treeDim[i][j]->leftChild;
				}
				if(treeDim[i][j]->rightChild!=NULL){  //右孩子 
					branch = F(deep - floor); 
					for(int k = 1 ; k <= branch ; k++){
						treeDim[i+k][j+k] = tmpR;
					}
					treeDim[i+branch+1][j+branch+1] = treeDim[i][j]->rightChild;
				} 
			} 	
		}
	}
	
	//根据二维数组打印二叉树格式 
	for(int i = 0 ; i < deepH ; i++){
		for(int j = 0 ; j < baseW ; j++){
			if(treeDim[i][j]==NULL){
				printf(" ");
			}else if(treeDim[i][j]==tmpL){
				printf("\/");
			}else if(treeDim[i][j]==tmpR){
				printf("\\");
			}else if(treeDim[i][j]!=NULL){
				printf("%c",treeDim[i][j]->word);
			}
		}
		printf("\n");
	}
	
	//结束时间 
	stop =GetTickCount();	
	printf("...Over.....OK...(%lld ms)\n\n",stop-start);
	
	getchar(); 
}
/* * * * * * * * * * * * * * * * * * * * * * * *
 *                         		       *       
 *  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){
	//开始时间 
	start =GetTickCount();  
	
	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");
	
	//结束时间 
	stop =GetTickCount();  
	printf("...Over.....OK...(%lld ms)\n\n",stop-start);
	
	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->rgAdrr);
		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->rgAdrr);
	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){
	//开始时间 
	start =GetTickCount();  
	
	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);
	
	//结束时间 
	stop =GetTickCount();	
	printf("...Over.....OK...(%lld ms)\n\n",stop-start);
	
	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;
				}
			}
		}
	}

	return tmpRoot;
}



/**
 *
 * Role:    Get Huffuman Tree
 * 
 * Explain: 从指定(*.dat)文件中获取获取哈夫曼树,给该树
 *			根结点Root赋值 . 
 *
 * @return : 无 
 *		
 */
void GetHuffumanTree(char *dir,struct Node **Root){ 
	//开始时间 
	start =GetTickCount();  

	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);      //哈夫曼树根结点 
	
	//结束时间 
	stop =GetTickCount();	
	printf("...Over.....OK...(%lld ms)\n\n",stop-start);
	
	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){
	//开始时间 
	start =GetTickCount();    
	
	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");
	
	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");
	
	//结束时间 
	stop =GetTickCount();	
	printf("...Over.....OK...(%lld ms)\n\n",stop-start);
	
	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){
	//开始时间 
	start =GetTickCount();    
	

	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("After UnZip FIle Is %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("\n"); 
	
	//结束时间 
	stop =GetTickCount();	
	printf("...Over.....OK...(%lld ms)\n\n",stop-start);

	fclose(file);
	fclose(huffuFile);
}

 

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>

#include"FileOperate.h"
#include"WordHzCount.h"
#include"HuffuTreeBuild.h"

//文件压缩项 
void ZIPFILE(char *src){
	char dir[strlen(src)+1];                                     //保存哈夫曼树的文件路径	
	strcpy(dir,src);
	dir[strlen(dir)-4]='\0';
	strcat(dir,".dat");
	
	char  *buff = FileInputStream(src);                            //获取指定文件中的资源 
	struct Word_Count_Array wCA = SingleChar_Hz(buff,strlen(buff));//统计指定资源文件中的字符出现频率 
	struct Node* Root = HuffumanTreeBuild(&wCA);                   //构建哈夫曼树Root 并且将字符编码存入全局wCA中 
	SaveHuffumanTree(dir,Root);                                    //将哈夫曼树存入文件中去 
	ShowHuffumanCode();                                            //展示字符编码 
	PaintBiTree(Root);                                             //展示哈夫曼树 
	
	FileZip(src);                                                   //文件压缩  
	   
}

//文件解压项 
void UNZIPFILE(char *dir){
	char huffile[strlen(dir)+10];                                     //保存哈夫曼树的文件路径	
	strcpy(huffile,dir);
	huffile[strlen(huffile)-7]='\0';
	strcat(huffile,".dat");
	
	struct Node *root;                                                //哈夫曼树根结点 
	GetHuffumanTree(huffile,&root);
	
	FileUnZip(dir,root);                                              //文件解压 
	
	PaintBiTree(root);                                                //展示哈夫曼树 
}

//帮助 
void HELP(){
	printf("\nYou need to enter two parameters.\n");
	printf("The first parameter is the functional option(the following values are available).\n");
	printf("'-zip' Or '-unzip' which means decompression and compression.\n");
	printf("The  second parameter is the filepath option(such as : 'D:\\a.txt').\n");
	printf("It is important to note that the input format cannot have any extra Spaces, and the format is '-option' 'path'\n");
} 


int main() {
	
	printf("Welcome to Huffman coding by Wang.\nNotice  : you can use the '-help' for help.\nLanguage: C \nAuthor  : luewang \nVersion : 1.0\n");
	char option[N];
	char path[N];
	while(1){
		printf("WHuff>>>");
		scanf("%s",option);	
		
		if(strcmp(option,"-help")==0){
			HELP();
		}else if(strcmp(option,"-zip")==0){
			scanf("%s",path);
			ZIPFILE(path);
		}else if(strcmp(option,"-unzip")==0){
			scanf("%s",path);
			UNZIPFILE(path);
		}else if(strcmp(option,"exit")==0){
			exit(0);
		}else{
			printf("Error: Please input the correct format. You can also use '-help' to view the help document\n");
		} 
	} 
	return 0;
}	

 

おすすめ

転載: blog.csdn.net/weixin_41237676/article/details/85121737