二叉鏈表實現哈夫曼編碼系統

題目說明

試編寫一個Huffman編碼系統,用於數據加密和解密。該系統應具有以下功能:

  1. 初始化:從鍵盤中可讀取通信所使用的字符集和每個字符的權值。例如下表。
  2. 加密 :利用初始化中的數據建立Huffman樹,對任意的可加密的字符串進行加密。
  3. 解密:對任何的加密結果進行解密。
字符 空格 A B C D E F G H
頻數 186 64 13 22 32 103 21 15 47
字符 I J K L M N O P Q
頻數 57 1 5 32 20 57 63 15 1
字符 R S T U V W X Y Z
頻數 48 51 80 23 8 18 1 16 1

擴展功能

  1. 支持從Excel表格導入字符集和權重值,格式見壓縮包中的weight.csv

測試數據

鏈接:點擊這裏下載

代碼實現

#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<string.h>
#define MAXSIZE 100 //定義字符串最大長度
#define INIT_STRING (String)malloc(sizeof(char)*MAXSIZE)

typedef int Status;
typedef char* String;

typedef struct node Node;
struct node{
	char data;
	int weight;
	Node* Lchild;
	Node* Rchild;
	Node* Father;
};

//字符串替換 
String strrpl(String str){
	int i=0;
	char ch = ',',new_ch = ' ';
	for(i=0;i<strlen(str);i++){ 
		if(str[i]==ch){
			str[i]=new_ch;
		}
	}
	return str;
} 

//讀取文件存入二叉鏈表中 
Node** readFile(){
	FILE* fp;
	fp = fopen("weight.csv","r");
	if(fp==NULL){
		printf("文件讀取失敗!");
		exit(0); 
	}
	int i = 0,count=0;
	Node** arr = (Node**)malloc(sizeof(Node*)*50); 
	String temp1 = INIT_STRING;
	int temp2 = 0;
	while(!feof(fp)){
		String temp = INIT_STRING;
		String str =INIT_STRING;
		fscanf(fp,"%s",temp);
		str = strrpl(temp);
		count = sscanf(str,"%s %d\n",temp1,&temp2);
		if(count<2){
			break;
		}
		arr[i] = (Node*)malloc(sizeof(Node));
		//printf("%s,%d\n",temp1,temp2);
		if(strcmp(temp1,"blank")==0){
			arr[i]->data = ' ';
		}else{
			arr[i]->data = temp1[0];
		}
		arr[i]->weight = temp2;
		arr[i]->Lchild = NULL;
		arr[i]->Rchild = NULL;
		i++;
	}
	arr[i] = NULL;
	return arr;
}

//*/
Node** readFile2(){
	FILE* fp;
	fp = fopen("data.csv","r");
	if(fp==NULL){
		printf("文件讀取失敗!");
		exit(0); 
	}
	int i = 0,count=0;
	Node** arr = (Node**)malloc(sizeof(Node*)*50); 
	String temp1 = INIT_STRING;
	int temp2 = 0;
	while(!feof(fp)){
		String temp = INIT_STRING;
		String str =INIT_STRING;
		fscanf(fp,"%s",temp);
		str = strrpl(temp);
		count = sscanf(str,"%s %d\n",temp1,&temp2);
		if(count<2){
			break;
		}
		arr[i] = (Node*)malloc(sizeof(Node));
		//printf("%s,%d\n",temp1,temp2);
		if(strcmp(temp1,"blank")==0){
			arr[i]->data = ' ';
		}else{
			arr[i]->data = temp1[0];
		}
		arr[i]->weight = temp2;
		arr[i]->Lchild = NULL;
		arr[i]->Rchild = NULL;
		i++;
	}
	arr[i] = NULL;
	return arr;
}

void getWeightFile(){
	FILE*fp;
	
	fp = fopen("data.csv","w+");	
	if(fp==NULL){
		printf("文件初始化失敗!");
		exit(0); 
	}
	int i=0,length=0,flag=0;
	char* ch=INIT_STRING;
	int weight=0;
	printf("請規定長度:");
	scanf("%d",&length);
	for(i=0;i<length;i++){
		printf("請輸入第%d組:\n",i+1);
		scanf("%s %d",ch,&weight);
		if(strcmp(ch,"blank")==0){
			fprintf(fp,"%s,%d\n","blank",weight);
			continue;
		}
		if(ch[0]<'A'||ch[0]>'Z'){
			flag = 1;
			break;
		}else{
			fprintf(fp,"%s,%d\n",ch,weight);
		}
	}
	if(flag){
		printf("輸入數據不合法!請重試!");
	}else{
		printf("\n");
		printf("輸入完畢");
	}
	printf("\n");
	printf("***********請按任意鍵返回***********");
	getch();
}
//*/

//從大到小排序 
void sort(Node** arr){
	int count = 0;
	for(count=0;arr[count]!=NULL;count++){
		//︿( ̄︶ ̄)︿ 數數看有多長 
	}
	int i,j;
	Node* temp;
	for(i=0;i<count;i++){
		for(j=i+1;j<count;j++){
			if(arr[j]->weight > arr[i]->weight){
				temp   = arr[j];
				arr[j] = arr[i];
				arr[i] = temp;
			}
		}
	}
	/*
	for(i=0;i<count;i++){
		printf("%c,%d\n",arr[i]->data,arr[i]->weight);
	}
	*/
	
}

//創建哈夫曼樹 
Node* createHuffTree(Node** arr){
	Node *head,*temp;
	int count;
	while(1){
		for(count=0;arr[count]!=NULL;count++){
		//︿( ̄︶ ̄)︿ 數數看有多長
		}
		if(count==1){
			head = arr[0];
			return head;
		}
		sort(arr);
		temp = (Node*)malloc(sizeof(Node));
		if(arr[count-1]->weight>arr[count-2]->weight){
			temp->Lchild = arr[count-1];
			temp->Rchild = arr[count-2];
		}else{
			temp->Lchild = arr[count-2];
			temp->Rchild = arr[count-1];
		}
		temp->weight = arr[count-1]->weight + arr[count-2]->weight;
		temp->data   = '#';
		temp->Lchild->Father = temp;
		temp->Rchild->Father = temp;
		
		arr[count-2] = temp;
		arr[count-1] = NULL;
	}
}

//前序遍歷 
void preOrderTravel(Node* np){
	if(np==NULL){
		return;
	}
	preOrderTravel(np->Lchild);
	printf("%c,%d\n",np->data,np->weight);
	preOrderTravel(np->Rchild);
}

//用前序遍歷找目標節點 
Node* preOrderTravel2(Node* np,char target){
	Node* temp=NULL;
	if(np==NULL){
		return NULL;
	}
	if(np->data==target){
		return np;
	}
	temp = preOrderTravel2(np->Lchild,target);
	if(temp!=NULL){
		return temp;
	} 
	temp = preOrderTravel2(np->Rchild,target);
	if(temp!=NULL){
		return temp;
	} 
}

//加密 
void encode(Node *tree){
	system("cls");
	String str = INIT_STRING;
	printf("請輸入要加密的字符串:"); 
	gets(str);
	int i,flag=0;
	for(i=0;str[i]!='\0';i++){
		if(str[i]==' '){
			continue;
		}
		if(str[i]<'A'||str[i]>'Z'){
			flag = 1;
			break;
		}
	}
	if(flag){
		printf("輸入字符串不合法!請重試!");
	}else{
		for(i=0;str[i]!='\0';i++){
		Node *np = preOrderTravel2(tree,str[i]);
		String temp1 = INIT_STRING;
		int strlen = 0;
		while(1){
			if(np == tree){
				break;
			}
			if(np->Father->Lchild == np){
				temp1[strlen] = '1';
			}else{
				temp1[strlen] = '0';
			}
			strlen++;
			temp1[strlen] = '\0';
			np = np->Father;
		}
		temp1 = strrev(temp1);
		printf("%s",temp1);
		}
	}
	
	printf("\n");
	printf("***********請按任意鍵返回***********");
	getch();
}

//解密 
void decode(Node *head){
	system("cls");
	String str = INIT_STRING;
	printf("請輸入要解密的字符串:"); 
	gets(str);
	int i,flag=0;
	for(i=0;str[i]!='\0';i++){
		if(str[i]!='0'&&str[i]!='1'){
			flag = 1;
		}
	}
	if(flag){
		printf("輸入字符串不合法!請重試!");
	}else{
		Node *np = head;
		String temp = INIT_STRING;
		for(i=0;str[i-1]!='\0';i++){
			if(np->Lchild==NULL){
				printf("%c",np->data);
				i--;
				np = head;
				continue;
			}
			if(str[i]=='1'){
				np = np->Lchild;
			}else{
				np = np->Rchild;
			}
		}
	}
	
	printf("\n");
	printf("***********請按任意鍵返回***********");
	getch();
}

void menu(){
	system("cls");
	printf("**************************************\n");
	printf("        1、對字符串進行加密\n");
	printf("        2、對加密結果進行解密\n");
	printf("        3、從鍵盤輸入\n");
	printf("        0、退出\n");
	printf("**************************************\n");
	Node **arr,*tree; 
	arr = readFile();
	tree = createHuffTree(arr);
	char n;
	n = getch();
	switch(n){
		case '1': encode(tree);break;
		case '2': decode(tree);break;
		case '3': getWeightFile();break;
		case '0': exit(1);
	}
}
int main(){
	while(1){
		menu();
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章