哈夫曼编码的各项操作

14天阅读挑战赛
努力是为了不平庸~

代码

 #include<iostream>
 #include<string.h>
 using namespace std;
 
 //顺序存储的数组元素结点数据结构
 typedef struct
 {
     int weight;//节点权值 
     int parent,lchild,rchild;//节点的双亲,左孩子,右孩子的下标 
 } HTNode,*HuffmanTree;
 //定义Huffman编码表,每一行对应一个原文字符的Huffman编码
 //以字符串形式存储编码结果
 typedef char **HuffmanCode;
 //Huffman树构造过程中,贪心选择函数
 void Select(HuffmanTree HT,int len,int &s1,int &s2)
 {
 //HT为存储的二叉树的结构体数组,len为选择的范围,主调函数中的从1到i-
 //1位置
 //构建过程中直接对HT数组中的元素信息进行更新维护
     int i=1,min1=0x3f3f3f3f,min2=0x3f3f3f3f;//先赋予最大值
     while(i<=len) 
     {
     	if(HT[i].weight<=min1 && HT[i].parent==0)
		 //如果权重小于最小的min1,将min1的值赋给min2,min1赋值 最小的
		 //并将相应的序号,赋给s1 s2 
     	{
     		min2=min1;
     		s2=s1;
     		min1=HT[i].weight;
     		s1=i;
		 }
		 else if(HT[i].weight<=min2 && HT[i].parent==0 && HT[i].weight>min1)
		 //如果仅剩两个数,且序号大的数大,将大的数赋给s2 
		 {
		 	min2=HT[i].weight;
		 	s2=i;
		 }
		 i++;
	 }
 }
 //求权重,w数组,记录权重,c数组,记录对应的字符 
 void getweight(int w[],char c[])
 {
 	string str;
 	getline(cin,str);//输入带空格的字符串 
 	int len=str.size(); //求字符串长度 
 	int a[60][60];             // 定义一个二维数组 
 	int i=1,j=1,k=0,p=1;       //a[i][0]记录字符,a[i][1]记录权重 
 	a[i][0]=str[k];            //先记录第一个字符 
 	c[i]=str[k];
    a[i][1]++;                //该字符对应的权重++ 
 	k++; 
 	while(k<len)
 	{
 		i=1;              //每次都从第一个记录的字符开始比较 
 		while(a[i][0]!=0)
 		{
 			if(a[i][0]==(int)str[k])     //如果 输入的字符与记录字符的相等
			                             // 权重++,并跳出while循环 
 			{
 				a[i][1]++;
 				k++;
 				p=0;
 				break;
			 }
			 else                   //不相等换下一个,进行比较 
			 {
			 	i++;
			 }
		 }
		 if(p)                      //p是作为判断,是否有与之对应的字符 
		 {                          //若没有,重新赋值一个 
		 	a[i][0]=str[k];
		 	c[i]=str[k];          
		 	
		 }
		 else                      //如果有,重新对p 赋值为1 
		 {
		 	p=1;
		 }
	 } 
	i=1;w[0]=0;
	while(a[i][0]!=0)             //对记录权重的数组 w进行赋值 
	{
		w[i]=a[i][1];
		i++;
	}
	

 }
 
 //构造Huffman树功能函数,n表示有n个叶子结点
 void CreatHuffmanTree(HuffmanTree &HT,int n)
 {
     //构造Huffman树HT,m存放根据叶子结点数计算的Huffman树结点总数
     //s1和s2分别表示HT结构体数组下标,用来指示元素所在位置
 
     int m,s1,s2,i=1;
      int w[60]={0};
      char c[60];
     getweight(w,c);//求权重
     if (n<=1) return;
     m=2*n-1;
     HT=new HTNode[m+1];  		//0号单元未用,所以需要动态分配 m+1个单元,HT[m]
     //表示根结点
    for(i=1;i<=m;i++)//将1-m号单元中的双亲,左孩子,右孩子的下标都初始化为0 
	{
		HT[i].parent=0;HT[i].lchild=0;HT[i].rchild=0;
	}
	for(i=1;i<=n;i++)   //输入前n个单元中叶子节点的权值 
	{
		HT[i].weight=w[i];
		
	 } 
	
	
 for(int i=n+1;i<=m;i++)//通过n-1次的选择、删除、合并来创建哈夫曼树 
 {
 	Select(HT,i-1,s1,s2);
 	// 选择两个双亲域为0且权值最小的节点,并返回它们在HT中的序号s1,s2 
 	HT[s1].parent=i;HT[s2].parent=i;
 	//得到新节点i,从森林中删除s1,s2,将s1和s2的双亲域由0改为1 
 	HT[i].lchild=s1;HT[i].rchild=s2;          // s1,s2分别作为i的左右孩子 
 	HT[i].weight=HT[s1].weight+HT[s2].weight; // i的权重为左右孩子权值之和 
 }
 
     /*――――――――――从n+1开始到m结束,构建Huffman树HT中的非叶子结点――――――――――*/
 
 }
 
 void CreatHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n)
 {
     //从叶子到根逆向求每个字符的Huffman编码,存储在编码表HC中,HT为构造的
     //Huffman树,n为要编码的字符数,即叶子节点数
     int i,start,c,f;
     HC=new char*[n+1];         						//分配n个字符编码的头指针矢量
     char *cd=new char[n];							//分配临时存放编码的动态数组空间
     cd[n-1]='\0';                         //编码结束符   
     for(int i=1;i<=n;i++)             //逐个字符求哈夫曼编码 
	 {
	 	start=n-1;                       //start开始时指向最后,即编码结束符位置 
	 	c=i;f=HT[i].parent;             //f指向节点c的双亲节点 
	 	while(f!=0)                    //从叶子节点开始向上回溯,直到根节点 
	 	{
	 		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;              //继续向上回溯 
	 		
		 }
		 HC[i]=new char[n-start];        //为第i个字符编码分配空间 
		 strcpy(HC[i],&cd[start]);       //将求得的编码从临时空间cd复制到HC的当前行中  
	  }       	
     /*――――――――――根据HT逐个构建HC中的Huffman编码――――――――
     ――*/
 
     delete cd;                            			//释放临时空间
 }
 
 //Huffman编码输出函数,HT[i]字符的编码为 HC[i]字符串中的内容
 void show(HuffmanTree HT,HuffmanCode HC,int n)
 {
     for (int i=1; i<=n; i++)
         cout<<HT[i].weight<<"   编码为   "<<HC[i]<<endl;
 }
 
int main()
 {
     HuffmanTree HT;  //定义一个哈夫曼树 
     HuffmanCode HC;  //定义一个哈夫曼编码 
     int n,m;
     cout<<"请输入叶子结点的个数:\n";
     cin>>n;         	//输入Huffman树的叶子结点个数
	 m=2*n-1;						
     getchar();       //吸收“\n” 
     cout<<"请输入数据: \n";
     
     CreatHuffmanTree(HT,n);  //创建哈夫曼树 
    CreatHuffmanCode(HT,HC,n);//求对应的哈夫曼编码 
     show(HT,HC,n);      //输出每个权重对应的哈夫曼编码 
	 	 cout<<"输入文本:\n";
	 	 string str;
	 	 getline(cin,str);//重新输入数据 
	 	 int len=str.size();//求输入字符串的长度
		  cout<<"再次输入数据:\n" ;
		  int w[60];
		  char c[60];
		  getweight(w,c);  //求字符数组c 
		  
		  for(int i=1;i<=n;i++)
		  {
		  	cout<<c[i]<<"   "<<HC[i]<<endl;//输出每个字符对应的哈夫曼编码 
		  }
		  cout<<"导出编码后的文本 : \n";
		  for(int i=0;i<len;i++)//遍历整个字符串 
		  {
		  	int j=1,p=1;    //p作为判断语句 
		  	while(p)
		  	{
		  		if(c[j]==str[i])//若字符与字符数组c中的相同,输出对应的哈夫曼编码 
		  		{
		  			cout<<HC[j];
		  			p=0;     //把p置为0,使循环结束 
				  }
				  else     //不相等,比较下一个 
				  {
				  	j++;
				  }
			  }
		  }
	 	 cout<<endl;
	 	 cout<<"输入编码串;\n";
	 	 string er;    
	 	 cin>>er;        //重新输入得到的编码串,用er储存 
	 	 
	 	 cout<<"输出译码后文本:\n";
	 	 int lon=er.size();  //求编码串的长度 
	 	 int k=m;     //k赋值为根节点序号m 
	 	 for(int i=0;i<lon;i++)
	 	 {
	 	 	if(er[i]=='0')   //如果输入的编码为0,则走向左孩子 
	 	 	{
	 	 		k=HT[k].lchild;
			  }
			  else       // 如果输入的编码为1,则走向右孩子 
			  {
			  	k=HT[k].rchild;
			  }
			  if(HT[k].lchild==HT[k].rchild)//如果一个节点的左右孩子序号相等,也就是都为空 
			  {                             //说明该节点为叶子节点,输出对应的字符 
			  	cout<<c[k];
			  	k=m;                       //重新从根节点进行遍历 
			  }
		  }
	} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值