哈夫曼编码-贪心算法

哈夫曼编码的基本思想时以字符的使用频率作为权构建一颗哈夫曼树,然后利用哈夫曼树对字符进行编码。构造一颗哈夫曼树,是将所有的编码的字符作为叶子结点,该字符在文件中的使用频率作为叶子结点的权值,以自底向上的方式,通过n-1次的”合并“运算后构造处一颗树,
核心思想是权值越大的叶子离根越近。
哈夫曼算法的贪心策略是每次从树的集合中取出没有双亲权值最小的两棵树作为左右子树,构造一颗新树新树根节点的权值为其左右孩子结点权值之和,将新树插入到树的集合中

#include
using namespace std;
#define Max 10000
const int maxn=1000+5;
int n;
struct h_Tree{
	double weight;//权重
	int lchild;//左儿子
	int rchild;//右儿子
	int parent;//父亲结点
	char value;//该结点的值
}Tree[maxn];//

struct Tree_Code{
	int bit[maxn];
	int start;
}Code[maxn];//

void Huff_Tree()
{	
	int x1,x2;
	double m1,m2;
	for(int i=1;i<=n-1;i++)//产生n-1个新的结点
	{
		m1=Max;
		m2=Max;
		x1=0;
		x2=0;
		for(int j=1;j<n+i;j++)//每个结点都要和新产生的结点进行比较
		{
			if(Tree[j].weight<m1&&Tree[j].parent==-1)//本着左儿子小右儿子大的元则构建树
			{
				m2=m1;
				x2=x1;
				x1=j;
				m1=Tree[j].weight;
			}
			else if(Tree[j].weight<m2&&Tree[j].parent==-1)
			{
				m2=Tree[j].weight;
				x2=j;
			}
		}//for
		Tree[x1].parent=i+n;//承上:要确定好结点的父亲
		Tree[x2].parent=i+n;
		Tree[i+n].lchild=x1;//启下:要确定该新结点赢具备的信息由两个儿子所给予
		Tree[i+n].rchild=x2;
		Tree[i+n].weight=m1+m2;
	}//for	
}
void Huff_Code()
{
	Tree_Code cd;
	int Parent;
	for(int i=1;i<=n;i++)
	{
		cd.start=n;
		int c =i;
		Parent = Tree[i].parent;
		while(Parent!=-1)
		{
			if(Tree[Parent].lchild==c)
			{
				cd.bit[cd.start--]=0;
			}
			else
			{
				cd.bit[cd.start--]=1;
			}
			c=Parent;//让该结点上滤找到结点的路径
			Parent=Tree[Parent].parent;
		}//while
		Code[i].start=1;
		for(int j=cd.start+1;j<=n;j++)
		{
			Code[i].bit[Code[i].start++]=cd.bit[j];
		}
	}//for依次求取哈夫曼中字母的编码
}
int main()
{
	cout<<"请输入结点数目:"<<endl;
	cin>>n;
	for(int i=1;i<=2*n-1;i++)//这里要对拓展结点进行初始化
	{
		Tree[i].lchild=-1;
		Tree[i].rchild=-1;
		Tree[i].parent= -1;
		Tree[i].weight=0.0;
	}//初始化	
	for(int i=1;i<=n;i++)
	{
		cin>>Tree[i].value>>Tree[i].weight;
	}//输入
	Huff_Tree();//构建hafuman树
	Huff_Code();//产生哈夫曼树编码
	cout<<"哈夫曼编码如下:"<<endl;
	for(int i=1;i<=n;i++)//输出
	{
		cout<<Tree[i].value<<"编码为:";
		for(int j=1;j<Code[i].start;j++)
			cout<<Code[i].bit[j]<<" ";
		cout<<endl;
	}
	return 0;
}

算法优化:
我们每次长生一个新的结点都要重所有结点中比较以后才能确定浪费了大量的时间。
可以采用优先队列
另外哈夫曼编码的长度我们也可以采用动态申请内存的方法这样右多少算就用多少没有浪费。

#include
#include
#include
using namespace std;
#define Max 10000
const int maxn=1000+5;
int n;
int A[maxn];
struct h_Tree{
	double weight;
	int lchild;
	int rchild;
	int parent;
	int num;
	char value;
	
	h_Tree(){};
	//默认初始化函数,必不可少的末尾右分号 
	h_Tree(double a,int b,int c,int d)//注意weight为浮点型数据 
	{
		weight=a;
		lchild=b;
		rchild=c;
		num=d;
	}//重载构造函数,把我们需要赋的值写入里面 
	bool operator<(const h_Tree& a)
	const{//排序队则给定//const必须要加的 
		return weight>a.weight;
	}
	
}Tree[maxn];

struct Tree_Code{
	int* bit;//留一个整型地址用来动态申请内存 
	int start;
}Code[maxn];

void Init(Tree_Code* T,int n)
{
	T->bit=(int *)malloc(sizeof(int )*n);
}//初始化 

void Huff_Tree() 
{	
	int x1,x2;
	double m1,m2;
	priority_queue<h_Tree> Q;
	for(int i=1;i<=n;i++)
		Q.push(h_Tree(Tree[i].weight,Tree[i].lchild,Tree[i].rchild,Tree[i].num));//把元素压入优先队列中 
	for(int i=1;i<=n-1;i++)
	{
		h_Tree t1=Q.top();
		Q.pop();//挑选出队列中最小的那个元素做为左儿子 
		h_Tree t2=Q.top();
		Q.pop();//挑选出队列中第二小的那个元素做为右儿子 
		double w=t1.weight+t2.weight;
		int l=t1.num;
		int r=t2.num;	
	//	cout<<"x1:"<
		Tree[l].parent=i+n;//构建结点的父亲为i+n新结点 
		Tree[r].parent=i+n;
		Tree[i+n].lchild=l;//左儿子为x1 
		Tree[i+n].rchild=r;//右儿子为x2 
		Tree[i+n].weight=w;	
	//父亲结点的产生并完善他们之间的关系 
		Q.push(h_Tree(w,l,r,i+n));//将新的结点压入堆栈		
	}//for	
}
Huff_Code()
{
	int index;
	int Parent;
	for(int i=1;i<=n;i++)
	{
		index=n;
		int c =i;
		Parent = Tree[i].parent;
		while(Parent!=-1)
		{
			if(Tree[Parent].lchild==c)//左儿子取0 
			{
				A[index--]=0;
			}
			else//右儿子取1 
			{
				A[index--]=1;
			}
			c=Parent;//结点向上传递 
			Parent=Tree[Parent].parent;
		}//while
		Code[i].start=1;
		Init(&Code[i],n-index);//动态申请一个大小正合适的内存 
		for(int j=index+1;j<=n;j++)
		{
			Code[i].bit[Code[i].start++]=A[j];
		}
	}//for依次求取哈夫曼中字母的编码
}
int main()
{
	cout<<"请输入结点数目:"<<endl;
	cin>>n;
	for(int i=1;i<=2*n-1;i++)
	{
		Tree[i].lchild=-1;
		Tree[i].rchild=-1;
		Tree[i].parent= -1;
		Tree[i].weight=0.0;
	}//对即将拓展的结点的初始化	
	//每合并一次减少两个结点产生一个结点,所以最多何以合并一个n-1次剩下一个结点。 
	for(int i=1;i<=n;i++)
	{
		cin>>Tree[i].value>>Tree[i].weight;
		Tree[i].num=i; 
	}
	Huff_Tree();
	Huff_Code();
	cout<<"哈夫曼编码如下:"<<endl;
	for(int i=1;i<=n;i++)
	{
		cout<<Tree[i].value<<"编码为:";
		for(int j=1;j<Code[i].start;j++)
			cout<<Code[i].bit[j]<<" ";
		cout<<endl;
	}
	return 0;
}

你可能感兴趣的:(算法模板)