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 ------------------------*/
2. 哈夫曼树操作测试
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;
}