#define n 4 //n叶子节点
#define m 2*n-1 //m总的节点
#define infinity 32767
struct node //哈夫曼树上每个节点
{
float weight;
int plink,llink,rlink;
};
struct codetype
{
int start; //编码的开始位置
char bits[n+1]; //编码的长度
};
struct element
{
char symbol;
codetype code;
};
node tree[m+1];
element table[n+1];
//一趟循环下来,得到最小而且没有plink的两个值的索引
void select(int s,int &x1,int &x2)
{
int i;
float v1,v2;
v1 = v2 = infinite; //v1,v2记录最小的两个元素的值
x1 = x2 = 0; //x1,x2记录最小的两个元素的位置
for(int i=0;i<=s;i++)
{//一趟循环下来,得到最小而且没有plink的两个值的索引
if(tree[i].plink == 0)
{//如果这个节点还没有弄到哈夫曼树中
if(tree[i].weight<v1)
{//v1比v2小
v2 = v1;
v1 = tree[i].weight; //得到v1,v2还是最小的两个
//索引
x2 = x1;
x1 = i;
}
else if(tree[i].weight <v2)
{//v1<x<v2,v1不变化,仅仅v2变化
v2 = tree[i].weight;
x2 = i;
}
}
}
}
//建立哈夫曼树 1..n是叶子节点,n+1..m是建立的节点
//结果就是从1..n是叶子节点,n+1到m是n2,其中n+1..m是依次建立的。m就是根节点
void setthuftree()
{
int i;
int x1,x2;
for(int i=n+1;i<=m;i++)
{//n+1..m,建立哈夫曼树
select(i-1,x1,x2); //x1,x2是符合条件的最小的两个元素的索引 ,i-1每次都在扩大,从n..m-1
tree[x1].plink = i;
tree[x2].plink = i;
tree[i].weight = tree[x1].weight+ tree[x2].weight;
tree[i].llink = x1;
tree[i].rlink = x2;
}
}
//根据建立好的哈夫曼树建立哈夫曼编码
void setthufcode()
{
int i;
int s;
int f;
codetype c;
for(int i=1;i<=n;i++)
{//对于每一个叶子节点进行哈夫曼编码
c.start = n+1;//因为哈夫曼编码是一个从根到叶子的顺序,所以得到的最靠近叶子节点的编码,实际上是后面的
s = i; //对tree的第i个元素进行编码
f = tree[s].plink; //得到第i个元素的父亲节点,然后就要一直遍历到哈夫曼树的根节点
do
{
c.start--;
if(s == tree[f].llink)
{//如果是它的左子树
c.bits[c.start] = '0';
}
else
{//如果是右子树
c.bits[c.start] = '1';
}
s = f;
f = tree[f].plink; //继续向根节点移动
}while(f)
table[i].code = c; //c已经是编码好的了
}
}
//哈夫曼过程
void huffman()
{
int i;
int j;
codetype c;
//初始化
for(int i= 0;i<n;i++)
{
cin>>table[i].symbol>>tree[i].weight; //最后table的codetype就是构建好的哈夫曼编码
}
//对1..n个叶子节点,构建哈夫曼树
setthuftree();
//得到哈夫曼code
setthufcode();
//输出
for(int i=1;i<=n;i++)
{
cout<<table[i].symbol<<" ";
c = table[i].code;
for(j = c.start;j<=n;j++)
{//输出哈夫曼编码0101...
cout<<c.bits[j];
}
}
}