題目說明
試編寫一個Huffman編碼系統,用於數據加密和解密。該系統應具有以下功能:
- 初始化:從鍵盤中可讀取通信所使用的字符集和每個字符的權值。例如下表。
- 加密 :利用初始化中的數據建立Huffman樹,對任意的可加密的字符串進行加密。
- 解密:對任何的加密結果進行解密。
字符 |
空格 |
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 |
擴展功能
- 支持從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));
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));
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;
}
}
}
}
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();
}
}