思路
- 每次挑选两个最小节点使它的父节点为权值之和,构造哈夫曼树,然后从底叶子结点向上遍历,是父亲的左孩子为0,右孩子为1。
注意
- 可以用new来分配内存。可以比malloc简单一点
-
- char *p=new char[n] 表示给p为指向一个大小为n的char数据区的头地址。
-
- char p=new char[n] 表示给p为指向一个大小为指针数值的头指正。
- 结构体的定义使用typedef与不使用会有点区别,结构体名的位置会有不同
- 一定要使用swap函数,为了使答案一致。
- 对于strcpy函数,有两点,一是地址的赋值,因此HC要采用引用型,二是地址是初位置的地址,一直到'\0'。因此可以令末位置为'\0',令指针不断递减来构建字符串。
- 用0xfffffff表示一个很大的数。
代码
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=101;
int w[maxn];
int n;
struct HTNode{
int weight;
int lchild,rchild,parent;
};
void select(HTNode *HT,int n,int &s1,int &s2){
int m=0x3fffffff;
for(int i=1;i<=n;i++){
if(HT[i].parent==0&&HT[i].weight<m){
s1=i;
m=HT[i].weight;
}
}
m=0xfffffff;
for(int i=1;i<=n;i++){
if(HT[i].parent==0&&HT[i].weight<m&&i!=s1){
s2=i;
m=HT[i].weight;
}
}
if(s1>s2) swap(s1,s2); //为了使答案唯一,s1放在前面。
}
void HuffmanCoding(HTNode* HT,char** &HC,int w[],int n){
//HT为哈夫曼树头指针,HC是一个数组指针,存储最后的编码结果,w权值,n为字符数。
if(n<=1) return;
int s1,s2; //找最下权值的下标
int m=2*n-1; //总节点数
HT=new HTNode[m+1]; //分配节点空间
for(int i=1;i<=n;i++){ //初始化叶子结点
HT[i].weight=w[i];
HT[i].lchild=HT[i].rchild=HT[i].parent=0;
}
for(int i=n+1;i<=m;i++){ //初始化非叶子节点
HT[i].parent=0;
}
for(int i=n+1;i<=m;i++){ //建立哈夫曼树
select(HT,i-1,s1,s2); //挑选父节点为0,权值最小的两个节点
HT[s1].parent=HT[s2].parent=i;
HT[i].lchild=s1;
HT[i].rchild=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;
}
HC=new char*[n+1]; //0不用
char cd[n]; //哈夫曼树的最多边为n-1条,只用n大小的空间
cd[n-1]='\0';
for(int i=1;i<=n;i++){
int start=n-1;
for(int c=i,f=HT[i].parent;f!=0;c=f,f=HT[c].parent){ //根节点的父指针为0
if(HT[f].lchild==c) cd[--start]='0'; //左孩子为0,右孩子为1
else cd[--start]='1'; //很好的方法,方便结尾定位
}
HC[i]=new char[n-start];
strcpy(HC[i],&cd[start]); //此处地址复制HC需要用引用符号
}
}
int main(){
while(scanf("%d",&n)!=EOF){
for(int i=1;i<=n;i++){
scanf("%d",&w[i]);
}
HTNode *HT;
char **HC;
HuffmanCoding(HT,HC,w,n);
for(int i=1;i<=n;i++){
printf("%s\n",HC[i]);
}
}
return 0;
}