赫夫曼树及其应用

#include<iostream>
#include<string>
#include<vector>
using namespace std;

#define N 4

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

int wt[N]={7,5,2,4};	//N个权值,分别对应A(7),B(5),C(2),D(4)

template<class T>
class HuffmanTree
{
public:
	void HuffmanCoding(HuffmanTree<T> *&HT,vector<string> &HC,const int *w,int n);
	void SelectTree(HuffmanTree *HT,int x,int &s1,int &s2);
private:
	T weight;	//权重
	T parent,lchild,rchild;		
};

template<class T>
void HuffmanTree<T>::HuffmanCoding(HuffmanTree *&HT,vector<string> &HC,const int *w,int n)
{
	//w存放n个字符的权值(均>0),构造赫夫曼数HT,并求出n个字符的赫夫曼编码HC
	if(n<=1)
		exit(-1);
	int m=2*n-1;	//生成的HuffmanTree中结点数目
	HT=new HuffmanTree<T>[m+1];	//0号单元未用
	HuffmanTree<T> *p=HT;
	p++;
	for(int i=1;i<=n;i++)
	{//根据给定的n个权值,构造n个带权值的根结点
		p->weight=*w;p->parent=0;p->lchild=0;p->rchild=0;
		p++;w++;
	}//for
	for(int i=n+1;i<=m;i++)
	{//HuffmanTree中不带权值的空白结点
		p->weight=0;p->parent=0;p->lchild=0;p->rchild=0;
		p++;
	}//for
	for(int i=n+1;i<=m;i++)	//建赫夫曼树
	{
		int s1,s2;
		SelectTree(HT,i-1,s1,s2);
		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;//构建新的树
	}//for
	
	//--------从叶子到根逆向求每个字符的赫夫曼树---------
	for(int i=1;i<=n;i++)
	{
		int c=i;
		T	f=HT[i].parent;
		while(f!=0)
		{
			if(HT[f].lchild==c)	//结点是其双亲的左结点
				HC[i].push_back('0');
			else
				HC[i].push_back('1');
			c=f;
			f=HT[f].parent;
		}//while
		reverse(HC[i].begin(),HC[i].end());
	}//for
}//HuffmanTrees*/

template<class T>
void HuffmanTree<T>::SelectTree(HuffmanTree *HT,int x,int &s1,int &s2)
{
	int i,j,firstmin,secondmin;	
	for(i=1;i<=x;i++)	//将还未被选中的第一颗HuffmanTree的标号赋给firstmin和secondmin
	{
		if(HT[i].parent!=0)	//跳过已经被选中的树结点树
			continue;
		else
		{
			firstmin=i,secondmin=i;
			break;
		}//else
	}//for
	for(j=i;j<=x;j++)	//由于前i-1颗树已被判定为使用过,故从第i颗数开始遍历
	{
		if(HT[j].parent==0)	//跳过父结点不是0的结点
		{
			if(HT[j].weight<HT[firstmin].weight)
			{
				secondmin=firstmin;//由于firstmin中每次比较都是存储最小标号
								   //当firstmin得到一个更小标号时,其当前标号便成为次小标号,赋给secondmin
				firstmin=j;	//将weight<HT[firstmain].weight的标号赋给firstmin
			}//				
			else if(HT[j].weight>=HT[firstmin].weight&&HT[j].weight<HT[secondmin].weight)
				{//当secondmin<i<=firstmin
					secondmin=j;
				}//else if
			else
				continue;
		}//if
	}//for

	if((firstmin==1)&&(secondmin==1))	//余下未被使用的结点的权值均大于第一个结点的权值
	{//找出剩余结点中最小的赋给secondmin
		for(int j=i+1;j<=x;j++)			//将接下来未被使用的第一个结点赋给secondmin
		{
			if(HT[j].parent==0)
			{
				secondmin=j;
				break;
			}
		}//for
		for(int j=secondmin+1;j<=x;j++)//将余下结点的权值与HT[secondmin].weight进行比较
		{
			if(HT[j].parent==0)
			{
				if(HT[j].weight<HT[secondmin].parent)
					secondmin=j;
			}//if
		}//for
	}//if
	s1=firstmin;s2=secondmin;
}//SelectTree

void main()
{
	int n=N;
	const int *w=wt;
	HuffmanTree<unsigned int> HTree,*HT;
	vector<string> HC(N+1);
	HTree.HuffmanCoding(HT,HC,w,n);
	cout<<"A,B,C,D依次对应的前缀编码如下:"<<endl;
	for(int i=1;i<=n;i++)
		cout<<HC[i]<<endl;
}//main
赫夫曼树及其应用_第1张图片

你可能感兴趣的:(赫夫曼树,最优二叉树,前缀编码)