#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