数据结构-哈夫曼树

#include<iostream>
#include<cstring>

using namespace std;
 
#define OK 1
#define ERROR 0
#define SIZE 27

typedef bool Status;

typedef struct {
	char code;
	unsigned int weight;
	unsigned int parent,lchild,rchild;
}HTNode,*HuffmanTree;

typedef char **HuffmanCode;//动态分配数组存储哈夫曼编码

int here, flag;


Status Select(HuffmanTree HT,int m,int &s1,int &s2){ //找出当前没有被使用过的两个最小的节点 
	int min1 = 0x3f3f3f3f;
	int min2 = 0x3f3f3f3f;
	HuffmanTree p = HT + 1;
	for(int i = 1; i <= m; i ++ , p ++){
		if(p->parent == 0 && min1 > p->weight){
			min1 = p->weight;
			s1 = i;
		}
	}
	p = HT + 1;
	for(int i = 1; i <= m; i ++ , p ++ ){
  		if(i != s1 && p->parent == 0)
 		  if(p->weight < min2){
    		min2 = p->weight;
    		s2 = i;
  		}
	}
	return 1; 
}

Status Scanf(int *w){
	int cnt = 0;
	int *p = w;
	while(cnt <= 26){
		cin >> *p;
		if(*p > 0){
			cnt ++ ;
			p ++ ;
		}
		else{
			cout<<"输入错误,请重新输入"<<endl;
		}
	}
	return 1;
}

Status InitHuffmanTree(HuffmanTree &HT,int *w,int n){//初始化哈夫曼树 
	int m = 2 * n - 1;
	HT=(HuffmanTree)malloc((m + 1)*sizeof(HTNode));
	if(!HT) return 0;
	HuffmanTree q = HT + 1;//0节点未使用 
	for(int i = 1;i <= n; i ++ , q ++ , w ++ ){
		q->code='l';//给叶子节点设标记 
		q->weight = *w;
		q->parent = 0;
		q->lchild = 0;
		q->rchild = 0;
	}//将n个叶子结点遍历,赋初值为0
	 
	for(int i = n + 1; i <= m; i ++ , q ++ ){
		q->code='f';//证明为非叶子节点 
		q->weight = 0;
		q->parent = 0;
		q->lchild = 0;
		q->rchild = 0;
	}//将剩余所有结点初始化权值为0
	return 1;
}

Status CreatHuffmanCode(HuffmanTree &HT, HuffmanCode &HC, int n){
	if(n <= 1) return 0;
	int m = 2 * n - 1;	//Huffman数总结点个数 
	int s1,s2;
	int st;//st 开始指向最后,即编码结束符位置
	int cnt,f; 
	for(int i = n + 1; i <= m; i ++ ){
		Select(HT, i - 1, s1, s2);//选parent为0的最小的两结点
		(HT + s1)->parent = i;
		(HT + s2)->parent = i;
		(HT + i)->lchild = s1;
		(HT + i)->rchild = s2;
		(HT + i)->weight = (HT + s1)->weight+(HT + s2)->weight;
    }//为非叶节点的结点赋值
	    
	HC = (HuffmanCode)malloc((n + 1)*sizeof(char*));//分配储存n个字符编码的编码表空间
	if(!HC)return 0;
	char*cd = (char*)malloc(n * sizeof(char));//分配临时存储字符编码的动态空间
	*(cd + (n - 1)) = '\0';//编码结束符
	for(int i = 1; i <= n; i ++ ){//从叶子节点开始逐个求编码 
		st = n - 1;
		for(cnt = i,f = (HT + i)->parent; f != 0; cnt = f, f = (HT + f)->parent){
			if((HT + f)->lchild == cnt){
				cd[ -- st] = '0';
			}
			else{
				cd[ -- st] = '1';
			} 
		}
		HC[i] = (char*)malloc((n - st)*sizeof(char));//n-st巧妙的节省了空间
		strcpy(HC[i], &cd[st]);//把求得编码的首地址从cd[st]复制到HC的当前行中 
	}
	free(cd);
	return 1;
}

Status CoutCode(HuffmanTree HT, HuffmanCode HC, int *w){//遍历输出 
	cout<<"字符"<<" "<<"编码"<<endl;
	char ch = 'a';
	int *p = w;
	for(int i = 1; i <= 27; i ++ ){
		if(i == 27){
   			cout<<" ";
		}
		else{
		   	printf("%c",ch + i - 1);
		}
		cout<<"  ";
		cout<<HC[i]<<endl;
	}
	return 1;
}

Status TransCode(HuffmanTree &HT,int n){
	char ch[80];
	int i = 0, m = 2 * n - 1;
 	cin>>ch;
 	cout<<"输入的二进制编码翻译成的字符为:";
    while(ch[i] && ch[i] != '\u0000'){
	if(ch[i] == '0'){
   		m = (HT + m)->lchild;//如果编码表示是左孩子,就继续向左下遍历 
  	}
	if(ch[i]=='1'){	 
   		m = (HT + m)->rchild;//如果编码表示是右孩子,就继续向右下遍历
  	}
	if((HT + m)->code == 'l'){  //如果当前遍历到的节点是叶节点 
   		if(m == 27){
   			cout<<" ";
	    }
		else{
		   	printf("%c",'a' + m - 1);
		}
   		m = 2 * n - 1;  //将结点重新放到哈夫曼树的根节点位置,重新开始,直到所有密码编译完成 
  	}	 
 	 	i++;  //i自增
 	}
 	return 1;
}

Status TransString(HuffmanTree &HT, HuffmanCode HC){
	char ch[105];
	cout<<"请输入要进行编译的字符串:";
	int g;
	char c;
	int k = 0;
	while((c=getchar())!='%'){//在遇到字符串结尾之前 
		ch[k]=c;
		k++;
	}
	ch[k] = '\0';
	cout<<"该字符串的编译结果为:";
	for(int i = 1; ch[i]; i ++ ){
		if(ch[i] == ' '){
			cout<<HC['{' - 'a' + 1];
		}
		else{
			cout<<HC[ch[i] - 'a' + 1];
		}
	}
	return 1;
}

void Menu(){
	cout<<"********************************************************"<<endl;
	cout<<"*       1.输入HuffmanTree的参数                        *"<<endl;
	cout<<"*       2.初始化HuffmanTree参数(含有26字母及空格)      *"<<endl;
	cout<<"*       3.创建HuffmanTree和编码表                      *"<<endl;
	cout<<"*       4.输出编码表                                   *"<<endl;
	cout<<"*       5.输入编码,并翻译为字符                        *"<<endl;
	cout<<"*       6.输入字符,并实现转码                          *"<<endl;
	cout<<"*       7.退出                                         *"<<endl;
	cout<<"********************************************************"<<endl;
	cout<<"请选择你要进行的操作:"; 
} 

int main()
{
	HuffmanTree HT;
	HuffmanCode HC;
	int n = 27;
	bool flag1 = false;//标记哈夫曼树和编码表是否建立 
	bool flag2 = false;//标记是否已输入参数 
	int *w = (int*)malloc(n * sizeof(int)); 
	if(!w) exit(-1);
	while(1){
		Menu();
		int x;
		cin>>x;
		if(x == 1){
			cout<<"请输入参数:";
			Scanf(w);
			cout<<"输入完成"<<endl;
			flag2 = true; 
		}
		else if(x == 2){
			if(flag2){
				InitHuffmanTree(HT,w,n);
				cout<<"HuffmanTree初始化成功!"<<endl;
			}
			else cout<<"请先输入Huffman的参数!"<<endl;	
		}
		else if(x == 3){
			if(flag2){
				CreatHuffmanCode(HT, HC, n);
				cout<<"创建成功!"<<endl;
				flag1 = true;
			}
			else cout<<"请先输入Huffman参数或初始化!"<<endl;
		}
		else if(x == 4){
			if(flag1){
				cout<<"编码表为:"<<endl;
				CoutCode(HT, HC, w);
			}
			else cout<<"请先创建HuffmanTree和编码表!"<<endl;
		}
		else if(x == 5){
			if(flag1){
				cout<<"请输入编码:";
				TransCode(HT,n);
				cout<<endl;
			}
			else cout<<"请先创建HuffmanTree和编码表!"<<endl;
		}
		else if(x == 6){
			if(flag1){
				cout<<"请输入字符串(以%结尾):";
				TransString(HT, HC);
				cout<<endl;
			}
			else cout<<"请先创建HuffmanTree和编码表!"<<endl;
		}
		else if(x == 7){
			cout<<"感谢使用!";
			break;
		}
		else{
			cout<<"请输入正确的操作序号"<<endl; 
		}
		cout<<endl; 
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值