函数SelectTwoMin(int upbound, HuffmanTree HT, int &s1, int &s2)是从1到upbound中找出father为0的节点赋给s1,s2,(为了保证答案唯一,请让s1的节点编号小于s2),函数HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n)是构造哈夫曼树以及计算哈夫曼编码。保证输入的权重值小于1000。
函数接口定义:
void SelectTwoMin(int upbound, HuffmanTree HT, int &s1, int &s2);
void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n);
其中 upbound 编号,HT是哈夫曼树,HC是哈夫曼编码,w是权值,n是叶子节点个数
裁判测试程序样例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int weight;
int parent;
int lchild;
int rchild;
} HTNode, *HuffmanTree;
typedef char ** HuffmanCode;
void SelectTwoMin(int upbound, HuffmanTree HT, int &s1, int &s2);
void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n);
int main() {
HuffmanTree ht;
HuffmanCode hc;
int n;
scanf("%d", &n);
int *w = (int *) malloc (n * sizeof(int));
for(int i = 0; i < n; ++ i)
scanf("%d", &w[i]);
HuffmanCoding(ht, hc, w, n);
for (int i = 1; i <= 2 * n - 1; ++ i) {
printf("%d %d %d %d\n",
ht[i].weight, ht[i].parent, ht[i].lchild, ht[i].rchild);
}
for (int i = 1; i <= n; ++ i)
printf("%s\n", hc[i]);
free(w);
free(ht);
for (int i = 1; i <= n; ++ i)
free(hc[i]);
return 0;
}
/* 你的代码将被嵌在这里 */
####输入格式:
第一行输入一个数n,表示叶子节点的个数,接下去输入n个整数,表示每个节点的值
####输出格式:
只要建树即可,输出已经确定了
输入样例:
4
1 2 3 4
输出样例:
1 5 0 0
2 5 0 0
3 6 0 0
4 7 0 0
3 6 1 2
6 7 3 5
10 0 4 6
110
111
10
0
代码:
void SelectTwoMin(int upbound, HuffmanTree HT, int &s1, int &s2)
{
int x1=0,x2=0;
int m1=1000;
int m2=1000;
//x1是最小数的下标,m1是记录x1的权值;
//x2是第二小数的下标,m2是记录x2的权值
for(int i=1;i<=upbound;i++)
{
/*如果一个数的权值比m1还小并且父节点为0,那么该数为最小数,
重新更新数据,并把原本的x1,m1赋给x2,m2*/
if(HT[i].parent==0&&HT[i].weight<m1)
{
x2=x1;
m2=m1;
x1=i;
m1=HT[i].weight;
}
/*如果有个数比m1大但比m2小,那么该数为第二小数,更新x2,m2即可*/
else if(HT[i].parent==0&&HT[i].weight<m2)
{
x2=i;
m2=HT[i].weight;
}
}
//把找到的数的下标赋给s1,s2
s1=x1;
s2=x2;
}
void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n)
{
//创建哈夫曼树
/*
1.初始化哈夫曼树,将题目输入的权重放进哈夫曼树中,把父节点,左孩子和右孩子都赋值为0(这三个变量都是记录下标)
2.创建一个新结点(n+1),找到权值最小的两个数后,把最小的赋给结点左孩子,第二小的数赋给结点右孩子
3.更新新结点左右孩子的父结点,均为当前下标,将新结点左右孩子的权值相加后赋给新结点的权值
*/
HT = (HuffmanTree)malloc(sizeof(HTNode)*(2*n));
HC = (char **)malloc(sizeof(char *)*(n+1));
for(int i=0;i<n;i++)//权重
HT[i+1].weight=w[i];
for(int i=1;i<=n;i++)//建立放哈弗曼编码的字符串数组
HC[i] = (char *)malloc(sizeof(char)*(n+1));
for(int i=1;i<=2*n-1;i++)//把父节点,左孩子和右孩子都赋值为0
{
HT[i].parent=0;
HT[i].lchild=0;
HT[i].rchild=0;
}
for(int i=n+1;i<=2*n-1;i++)
{
int s1=0,s2=0;//每次都要初始化
SelectTwoMin(i-1,HT,s1,s2);//找到最小的两个数s1,s2
HT[i].lchild=s1;//最小的赋给结点左孩子
HT[i].rchild=s2;//第二小的数赋给结点右孩子
HT[s1].parent=i;
HT[s2].parent=i;
HT[i].weight=HT[s1].weight+HT[s2].weight;
}
//计算哈夫曼编码
/*
1.用一个临时字符串储存编码,因为是从孩子结点往上找父结点,所以是逆着找,从后往前存,父结点等于0时即为不存在,说明当前结点为根结点
2.先找当前结点的父节点,用c储存孩子节点下标,f储存父结点下标,然后在父结点位置判断当前结点是左孩子还是右孩子
3.是左孩子就赋值编码为‘0’,右孩子就赋‘1’
4.判断完左右孩子后重新更新c和f,c=f;f=HT[c].parent
5.把临时字符串拷贝到编码字符串数组中(HC[i])
*/
for(int i=1;i<=n;i++)//i=1是因为哈夫曼树从1开始储存,只算输入的权重的编码,后面计算的权重不需要算编码
{
char code[n];
int start=n-1;
code[n-1]='\0';//字符串的最后必须是'\0'
int c=i;
int f=HT[i].parent;
while(f!=0)
{
start--;
if(HT[f].lchild==c)//左孩子
{
code[start]='0';
}
else
{
code[start]='1';
}
c=f;
f=HT[c].parent;
}
HC[i]=(char *)malloc(sizeof(char)*(n-start));
strcpy(HC[i],&code[start]);//拷贝
}
}