1. 哈夫曼树结构和操作定义
HuffmanTree.h
//功能:霍夫曼树结构体 typedef struct{ int weight; //权值 int parent; //父节点序号 int left; //左子树序号 int right; //右子树序号 }HuffmanTree; typedef char *HuffmanCode; //Huffman编码指针 /*---------------------HuffmanTree树所有操作原型声明 start ------------------------*/ //功能:创建HuffmanTree void CreateTree(HuffmanTree *ht, int n, int *w); //功能:从n个节点中选择parent节点为0,权重最小的两个节点 void SelectNode(HuffmanTree *ht, int n, int *bt1, int *bt2); //功能:根据HuffmanTree生成每个字符的哈夫曼编码 //倒序编码:从叶节点开始向根节点查找,生成各叶节点的哈夫曼编码 void HuffmanCoding(HuffmanTree *ht, int n, HuffmanCode *hc); //功能:将一个字符串转换为哈夫曼编码 void Encode(HuffmanCode *hc, char *alphabet, char *str, char *code); //功能:将一个哈夫曼编码组成的字符串转换为明文字符串 void Decode(HuffmanTree *ht, int m, char *code, char *alphabet, char *decode); /*---------------------HuffmanTree树所有操作原型声明 end --------------------------*/ /*---------------------HuffmanTree树所有操作具体实现 start ------------------------*/ //功能:创建HuffmanTree void CreateTree(HuffmanTree *ht, int n, int *w){ int i, m=2*n-1; //m为节点总数 int bt1, bt2; //保存权重最小的节点序号 if(n<=1){ printf("只有一个叶子节点,无法创建HuffmanTree!!"); return; } //初始化叶节点 for(i=1; i<=n; i++){ ht[i].weight = w[i-1]; ht[i].parent = 0; ht[i].left = 0; ht[i].right = 0; } //清空非叶节点 for(; i<=m; i++){ ht[i].weight = 0; ht[i].parent = 0; ht[i].left = 0; ht[i].right = 0; } //逐个计算非叶节点,创建HuffmanTree(根节点的编号为m) for(i=n+1; i<=m; i++){ SelectNode(ht, i-1, &bt1,&bt2); ht[bt1].parent = i; ht[bt2].parent = i; ht[i].left = bt1; ht[i].right = bt2; ht[i].weight = ht[bt1].weight + ht[bt2].weight; } return; } //功能:从n个节点中选择parent节点为0,权重最小的两个节点 void SelectNode(HuffmanTree *ht, int n, int *bt1, int *bt2){ int i; HuffmanTree *ht1, *ht2, *t; ht1 = ht2 = NULL; for(i=1; i<=n; i++){ if(!ht[i].parent){ if(ht1==NULL){ ht1=ht+i; continue; } if(ht2==NULL){ ht2=ht+i; if(ht1->weight > ht2->weight){ t = ht2; ht2 = ht1; ht1 = t; } continue; } if(ht1 && ht2){ if(ht[i].weight <= ht1->weight){ ht2 = ht1; ht1 = ht+i; } else if(ht[i].weight < ht2->weight) ht2 = ht + i; } } } //保证二叉树左侧为叶节点 if(ht1>ht2){ *bt1 = ht2-ht; *bt2 = ht1-ht; } else{ *bt1 = ht1-ht; *bt2 = ht2-ht; } return; } //功能:根据HuffmanTree生成每个字符的哈夫曼编码,n为叶子节点数 void HuffmanCoding(HuffmanTree *ht, int n, HuffmanCode *hc){ char *cd; int start, i; int current, parent; cd = (char *)malloc(sizeof(char)*n); //用来临时存放一个字符的编码结果 cd[n-1] = '\0'; for(i=1; i<=n; i++){ start=n-1; current=i; parent = ht[current].parent; while(parent){ if(current==ht[parent].left) cd[--start]='0'; else cd[--start]='1'; current = parent; //设置当前节点指向父节点 parent = ht[parent].parent; //获取当前节点的父节点序号 } hc[i-1] = (char *)malloc(sizeof(char)*(n-start)); strcpy(hc[i-1], &cd[start]); } free(cd); return; } //功能:将一个字符串转换为哈夫曼编码 void Encode(HuffmanCode *hc, char *alphabet, char *str, char *code){ int len=0, i=0, j; code[0]='\0'; while(str[i]){ j=0; while(alphabet[j] != str[i]) //查哈夫曼编码表 j++; strcpy(code+len, hc[j]); len +=strlen(hc[j]); i++; } code[len] = '\0'; return; } //功能:将一个哈夫曼编码组成的字符串转换为明文字符串 void Decode(HuffmanTree *ht, int m, char *code, char *alphabet, char *decode){ int position=0, i, j=0; m=2*m-1; while(code[position]){ for(i=m; ht[i].left &&ht[i].right; position++){//根节点标号为m,从根节点出发查找叶子节点 if(code[position]=='0') i=ht[i].left; else i=ht[i].right; } decode[j]=alphabet[i-1]; //得到一个字母 j++; } decode[j]='\0'; return; } /*---------------------HuffmanTree树所有操作具体实现 start ------------------------*/
HuffmanTreeTest.cpp
#include<stdio.h> #include<stdlib.h> #include<string.h> #include "HuffmanTree.h" int main(){ int i, n, m, select; //char test[] ="DBDBDABDCDADBDADBDADACDBDBD"; //测试字符串 char testStr[50]; char encode[100], decode[100]; //char alphabet[]={'A','B','C','D'}; char *alphabet; //int w[] = {5, 7, 2, 13}; //4个字符的权值 int *w; HuffmanTree *ht; HuffmanCode *hc; //哈夫曼编码字符串指针 do{ printf("---------------------------\n"); printf("1.创建HuffmanTree 2.根据HuffmanTree生成哈夫曼编码\n"); printf("3.利用哈夫曼编码加密字符串 4.利用哈夫曼编码解密“加密字符串”\n"); printf("0.退出\n"); printf("请选择执行的操作序号:"); fflush(stdin); scanf("%d", &select); switch(select){ case 1: printf("请输入叶子节点的数目:"); fflush(stdin); scanf("%d", &n); m=2*n-1; ht=(HuffmanTree *)malloc((m+1)*sizeof(HuffmanTree)); //申请内存,保存哈夫曼树 if(!ht){ printf("内存分配失败!!"); exit(0); } alphabet = (char *)malloc((n+1)*sizeof(char)); w = (int *)malloc((n+1)*sizeof(int)); for(int j=0; j<n; j++){ printf("请输入第%d个叶子节点及其权值:",j+1); fflush(stdin); scanf("%s %d", &alphabet[j], &w[j]); } CreateTree(ht, n, w); break; case 2: if(!ht){ printf("请先创建HuffmanTree!!"); continue; } hc=(HuffmanCode *)malloc(n*sizeof(char *)); //申请内存,保存哈夫曼树 if(!hc){ printf("内存分配失败!!"); exit(0); } HuffmanCoding(ht, n, hc); for(i=1; i<=n; i++) printf("字母:%c,权重:%d,编码为%s\n", alphabet[i-1], ht[i].weight, hc[i-1]); break; case 3: printf("请输入需要编码的字符串:"); fflush(stdin); scanf("%s", testStr); Encode(hc, alphabet, testStr, encode); printf("字符串:%s\n,编码后为:%s\n", testStr,encode); break; case 4: Decode(ht, n, encode, alphabet, decode); printf("\n编码:%s\n,解码后为:%s\n", encode,decode); break; } }while(select != 0); system("pause"); return 1; }