#include"iostream"
#include<iomanip>
#include<string>
using namespace std;

struct HTNode
{
	int weight;													// 权值，设为整型
	int parent;													// 双亲位置
	int lchild;													// 左孩子位置
	int rchild;													// 右孩子位置
};


void select(HTNode *HT,int k,int &i1,int &i2)					// 在前K-1个结点中选择权值最小的两个根结点i和j
{
	int m1,m2;
	m1=m2=32767; //
	i1=i2=0;
	for(int j=0;j<k;j++)
	{
		if(HT[j].weight<m1 && HT[j].parent==-1)
		{
			m2=m1,i2=i1;
			m1=HT[j].weight;
			i1=j;
		}
		else if(HT[j].weight<m2 && HT[j].parent==-1)
		{
			m2=HT[j].weight;
			i2=j;
		}
	}
}
// 算法5.16															// 构造哈夫曼树
void HuffmanTree(HTNode *&HT, int *w, int n)
{																	// n是叶子结点的个数，w是叶子结点的权值数组
	HTNode *p;
	int k,i;
	int i1,i2;
	p=HT;
	for(i=0;i<2*n-1;i++)
	{																// 设置初始状态，所有结点的指针为空
		HT[i].weight=0;
		HT[i].parent=-1;
		HT[i].lchild=-1;
		HT[i].rchild=-1;
	}
	for(i=0;i<n;i++)
	{																// 前n个结点的权值分别为个结点的权值
		HT[i].weight=w[i];
	}
	for(k=n;k<2*n-1;k++)
	{																// 构造最优二叉树
		select(HT,k,i1,i2);											// 在前K-1个结点中选择权值最小的两个根结点i1和i2
		HT[i1].parent=k;
		HT[i2].parent=k;
		HT[k].weight=HT[i1].weight+HT[i2].weight;
		HT[k].lchild=i1;
		HT[k].rchild=i2;
	}
}


void DispHT(HTNode *HT,int n)										// 显示哈夫曼树存储	
{
	HTNode *p;
	p=HT;
	cout<<"k"<<setw(7)<<"Weight"<<setw(7)<<"parent"
		<<setw(7)<<"lchild"<<setw(7)<<"rchild"<<endl;
	for(int k=0;k<2*n-1;k++)
	{
		cout<<k<<setw(7)<<(p+k)->weight<<setw(7)<<(p+k)->parent
			<<setw(7)<<(p+k)->lchild<<setw(7)<<(p+k)->rchild<<endl;
	}
}

//算法5.17															// 构建哈夫曼编码
void CreateHFCode(HTNode *HT, int n, char **HC)
{
	int i,start,c,f;
	char *cd;
	cd=new char[n];
	cd[n-1]='\0';
	for(i=0;i<n;i++)
	{
		start=n-1;
		c=i;
		f=HT[i].parent;
		while(f!=-1)
		{
			if(HT[f].lchild ==c)
				cd[--start]='0';
			else
				cd[--start]='1';
			c=f;f=HT[f].parent ;
		}	
		cout<<endl;
		HC[i]=new char[n-start];
		HC[i]=&cd[start];
		int j=0;
		while(HC[i][j]!='\0')										// 显示编码
		{
			cout<<HC[i][j];
			j++;
		}
	
	}
	delete cd;
	cout<<endl;
}


int op;
	
void main()
{
	int *w;															// 权值数组
	int n;															// 权值个数
	int i;															// 工作变量
	HTNode *HT;														// 哈夫曼树
	char **HC;
	do
	{
		cout<<"1-输入结点权值"<<endl;
		cout<<"2-生成最优二叉树"<<endl;
		cout<<"3-求哈夫曼编码"<<endl;
		cout<<"4-退出程序"<<endl;
		cout<<"请选择操作(1~4)：";
		cout<<"\b\b";
		cin>>op;
		switch(op)
		{
		case 1:
			cout<<"测试案例"<<endl;
			cout<<"7,5,2,3,5,6"<<endl;
			cout<<"请输入结点的个数：";
			cin>>n;
			w=new int[n];
			cout<<"请依次输入权值："<<endl;
			for(i=0;i<n;i++)
			{
				cout<<"请输入第"<<i+1<<"个权值：";
				cin>>w[i];
			}
			break;
		case 2:
			HT=new HTNode[2*n-1];										// 申请最优二叉树存储空间
			HuffmanTree(HT,w,n);
			cout<<"创建的哈夫曼树为：\n";
			DispHT(HT,n);
			system("pause");
			break;
		case 3:
			HC=new char*[n];											// 存储哈示曼编码
			cout<<"哈夫曼编码为：\n";
			CreateHFCode(HT, n, HC);
			break;
		case 4:
			cout<<"结束运行，Bye-Bye!"<<endl;
			break;
		}
	}while(op!=4);
}