赫夫曼树-Huffman编码

首先感叹,Huffman真牛逼!!

尽量把文件压缩到最小

通过最优排序,大数据把人们最常用的字符放到树前面,以实现最小编码。

大致说一下原理,贴一下代码

1:用户提供常用字符,建立一棵最优树

2:得到每一个字符的编码code

3:用户输入0和1,通过遍历最优树实现解码

说起来很容易,编码设计到队列和二叉树,确实不容易敲出来

接下来敲一下代码:/*注:没使用头文件,分文件写,考虑看家看的明白*/

/*还有就是头节点应该和普通节点不一样的,但是Debug时候出现不同struct类型不能赋值,所以干脆使用同一个struct了,比较占用空间,各位看官知道就行,当然可以优化*/

/*
输入文本,建立队列
生成huffman 树
输入编码,输出字符文本
*/
#include <malloc.h>
#include <iostream>
using namespace std;
typedef  struct  ht_node//huffman树节点
{
	char  data;
	struct   ht_node  *left,*right;
}*TYPE;

typedef  struct  quene_node//队列节点
{
	TYPE  val;//树类型
	unsigned int size;
	unsigned  int  priority;//优先级
	struct  quene_node  *next;//后继
}*Q_node;


typedef  struct  table_node
{
	char symbol;//字符存放
	char *code;
	struct  table_node *next;
}Table_node;


typedef  struct  table
{
	Table_node *first,*next;
}*Table;


void add_quene(Q_node &hufquene,TYPE &aux,unsigned  int  priority)//参数:队列头节点,树节点,优先级
{
	if(hufquene->size==256)
	{
		cout<<"Quene is full !!";
		return;
	}//否则建立队列节点
	Q_node temp=(Q_node)malloc(sizeof(quene_node));
	temp->priority=priority;
	temp->val=aux;

///////////////////////DEBUG/////////////////////////////////
	if(hufquene->size==0||hufquene->next==NULL)//只有头节点
	{
		//把元素插入队列
		temp->next=NULL;
		hufquene->next=temp;
		hufquene->size++;
	}else
	{
		
		//要进行比较后按顺序优先级从小到大排列
		Q_node  itertor=hufquene;//建立迭代节点,指向第一个节点


		while(itertor->next!=NULL)//队列中存在元素
		{
			if(priority<=itertor->next->priority)//从第二个节点开始比较
			{
				hufquene->size++;
				temp->next=itertor->next;
				itertor->next=temp;//头插法
				return;
			}
			
			itertor=itertor->next;
		}
		if(itertor->next==NULL)
		{
			temp->next=NULL;
			itertor->next=temp;
			hufquene->size++;
			return;
		}
		

	}

}


TYPE  getquene(Q_node &hufquene)
{
	TYPE  returnvalue;
	if(hufquene->size>0)
	{
		Q_node tree_node= hufquene->next;
		returnvalue=tree_node->val;
		hufquene->next=tree_node->next;
		hufquene->size--;
	}else
	{
		cout<<"Empty!!";
	}
	return  returnvalue;//返回树节点

}
TYPE buildtree(char *inputstring)
{
	int *probablity=(int *)malloc(sizeof(int)*256);//分配地址
	for(int i=0;i<256;i++)
		probablity[i]=0;//初始化
	for(int j=0;inputstring[j]!='\0';j++)
	{
		probablity[(inputstring[j])]++;
	}//统计字符出现次数
	Q_node hufquene;//定义一个头节点

	//////初始化头节点
	hufquene=(Q_node)malloc(sizeof(quene_node));
	hufquene->next=NULL;
	hufquene->size=0;
	///////////
	//生成队列
	for(int k=0;k<256;k++)
	{
		if(probablity[k]!=0)//存在字符
		{
			TYPE  aux=(TYPE)malloc(sizeof(ht_node));
			aux->data=(char)k;
			aux->left=NULL;
			aux->right=NULL;//为每一个字符分配一个树节点
			//插入队列
			add_quene(hufquene,aux,probablity[k]);
		}

	}
	//生成Huffman树
	while(hufquene->size!=1)
	{
		Q_node  tyust=hufquene->next;
		unsigned int num=tyust->priority;
		num+=tyust->next->priority;
		TYPE left=getquene(hufquene);
		TYPE right=getquene(hufquene);
		TYPE huff_tree=(TYPE)malloc(sizeof(ht_node));
		huff_tree->left=left;
		huff_tree->right=right;
		add_quene(hufquene,huff_tree,num);//再次插入
	}
	TYPE  root=(TYPE)malloc(sizeof(ht_node));
	root=getquene(hufquene);
	return root;
}
void  travertree(TYPE tree_node,Table &link,int k,char code[256])
{
	if(tree_node->left==NULL&&tree_node->right==NULL)//叶子
	{
		code[k]='\0';//添加结束
		Table_node  *aux=(Table_node*)malloc(sizeof(Table_node));
		aux->code=(char*)malloc(sizeof(char)*(strlen(code)+1));
		strcpy(aux->code,code);
		aux->symbol=tree_node->data;
		aux->next=NULL;
		if(link->first==NULL)
		{
			link->first=link->next=aux;
		}else
		{
			link->next->next=aux;
			link->next=aux;
		}		

	}
	if(tree_node->left!=NULL)//左子树不为0
	{
		code[k]='0';
		travertree(tree_node->left,link,k+1,code);
	}
	if(tree_node->right!=NULL)
	{
		code[k]='1';
		travertree(tree_node->right,link,k+1,code);
	}
}
Table build_table(TYPE tree_node)//建立
{
	Table  tytable=(Table)malloc(sizeof(table));
	tytable->first=NULL;
	tytable->next=NULL;
	char code[256];
	int k=0;
	travertree(tree_node,tytable,k,code);
	return tytable;

}
void  decode(TYPE root,char *str)//解码
{
	int j=0;
	TYPE temp=root;
	cout<<"你输入的编码是:"<<endl;
	while(str[j]!='\0')
	{
		cout<<str[j++];
	}cout<<endl;
	cout<<"解码:"<<endl;
	for(int i=0;str[i]!='\0';i++)
	{
		if(temp->left==NULL&&temp->right==NULL)
		{
			cout<<temp->data;
			temp=root;//碰到叶子后从根重新开始
		}
		if(str[i]=='0')
		{
			temp=temp->left;//0向左走
		}
		if(str[i]=='1')
		{
			temp=temp->right;
		}	
	}
}
void  main()
{
	TYPE  root=buildtree("Hello world I am CPP");//根据大数据生成最优树
	Table mark_table=build_table(root);//返回生成的最优排列
	decode(root,"00011101111101");//还没找到对应编码多出的舍弃不要
	cout<<endl;
}

猜你喜欢

转载自blog.csdn.net/shuiyihang0981/article/details/82623930