哈夫曼树及哈夫曼编码

哈夫曼编码:

HC[i]是二维的字符串数组,用来存放7个由0和1组成的字符串

cd[start]是字符数组,用来存放不断回溯的过程中得到的0或者1,'/0'是字符串结束标志,放在末尾

 

 最终HC[i]表格为:

基本代码如下:

#include <iostream> 
using namespace std;
#include <string>
#include <cstring>
//-----哈夫曼树的存储表示----- 
typedef struct{
	int weight;//结点的权值
	int parent,lchild,rchild;//结点的双亲、左孩子、右孩子的下标 
}HTNode,*HuffmanTree;//动态分配数组存储哈夫曼树 
 
void Select(HuffmanTree HT,int n,int &s1,int &s2){
	int a= 1e4,b= 1e4;//选两个很大的值进行比大小 
    for(int i=1;i<=n;i++){
        if(HT[i].parent == 0){//一开始双亲都为0
            if(HT[i].weight < b){
                a = b;
                s1 = s2;
			//如果找到比b还小的,则将a变为b,s2赋给s1,继承b(原来最小的值) 		 
                b = HT[i].weight;
                s2 = i;//取出最小的结点编号 
            }else if(HT[i].weight < a){
			/*第一个条件语句满足后,即便第二个条件语句也满足,也不会执行第二个括号。
			所以这是用来在第一个条件语句不满足后,用来比较出第二小的*/ 
                a = HT[i].weight;
                s1 = i;//取出第二小的结点编号 
            }
        }
    }
}
//构造哈夫曼树 
void CreateHuffmanTree(HuffmanTree &HT,int n){
//------------初始化哈夫曼树HT------------
	if(n<=1) return;
	int m=2*n-1;//n个结点构造出哈夫曼树后的结点总个数 
	HT=new HTNode[m+1]; //0号单元未用,所以需要动态分配m+1个单元,HT[m]表示根节点//HT是指针,指向结点 
	for(int i=1;i<=m;++i){//将1~m号单元中的双亲、左孩子,右孩子的下标都初始化为0 
		HT[i].parent=0;
		HT[i].lchild=0; 
		HT[i].rchild=0; 
	} 
	cout<<"请输入"<<n<<"个叶子结点的权值:"<<endl; 
	for(int i=1;i<=n;i++){
		cin>>HT[i].weight;//输入前n个单元各结点的权值 
	} 
//------------创建哈夫曼树------------ 
	for(int i=n+1;i<=m;i++){//n+1是新合并出来的第一个结点的编号i 
		int s1,s2;//因为select函数传的是变量,所以要先声明,如果是定值就不需要先声明 
		Select(HT,i-1,s1,s2);//在HT[k](1<=k<=i-1)中选择两个其双亲域为0且权值最小的结点,并返回它们在HT中的序号s1和s2
		//得到新结点i,从森林中删除s1和s2,将s1和s2的双亲域由0改为i
		HT[s1].parent=i;
		HT[s2].parent=i;
		//s1,s2分别作为i的左右孩子
		HT[i].lchild=s1; HT[i].rchild=s2; 
		//i的权值为左右孩子权值之和
		HT[i].weight=HT[s1].weight+HT[s2].weight;
	}
} 
//输出哈夫曼树 
void printHuffmanTree(HuffmanTree &HT,int m){
	cout<<"哈夫曼树为:"<<endl; 
	for(int i=1;i<=m;i++){//注意i不要从0开始,因为0号位没有权值 
		cout << HT[i].weight << " " << HT[i].parent << " " <<HT[i].lchild << " "<< HT[i].rchild << endl;
	}
}
//哈夫曼编码
typedef char **HuffmanCode;//一个指针指向的是另外一个指针,我们就称它为二级指针,或者指向指针的指针
void CreateHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n){
//从叶子到根逆向求每个字符的哈夫曼编码,存储在编码表HC中 
	HC=new char*[n+1];//分配存储n个字符编码的编码表空间,指针HC指向他们 
					  /* char *[]是数组,数组中的元素是字符串。在C语言中字符串常量的本质表示其实是一个地址,如char *s="China";等价于char s[]="China";
					     char *s[]={"China","French","America","German"};*/
	char *cd=new char[n]; //分配临时存放每个字符编码的动态数组空间
	cd[n-1]='\0';//开辟了n个空间,cd[n-1]是最后一格,放'\0'
	for(int i=1;i<=n;i++){
		int start=n-1;//start开始时指向最后,即编码结束符位置'\0' 
		int c=i;//c是结点下标 
		int f=HT[i].parent;//f指向结点c的双亲结点,f表示当前结点parent域的值 
		while(f!=0){//f=0意为 直到找到双亲域为0的结点作为根结点 
			--start;//回溯一次start向前指一个位置
			if(HT[f].lchild==c)  
				cd[start]='0';//结点c是f的左孩子,则生成代码0
			else 
				cd[start]='1';//结点c是f的右孩子,则生成代码1
			c=f; f=HT[f].parent;//继续向上回溯 
		}//求出第i个字符的编码
		HC[i]=new char[n-start];//为第i个字符编码分配空间
		strcpy(HC[i],&cd[start]);//将求得的编码临时从cd复制到HC的当前行中 
	} 
	delete cd;//释放临时空间 
}
int main(){
	HuffmanTree HT; 
	int n=8;
	CreateHuffmanTree(HT,n);
	printHuffmanTree(HT,2*n-1);
	
	HuffmanCode HC;
	CreateHuffmanCode(HT,HC,8);
	cout<<"哈夫曼编码为:"<<endl;
	for(int i=1;i<=8;i++){
        cout<< HC[i] <<endl;
    }
	system("pause");
}

实现:

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值