哈夫曼树

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


你可能感兴趣的:(哈夫曼树,HuffmanTree)