4.codeup-哈夫曼树-自顶向下的哈夫曼树

82 阅读1分钟

思路

  • 构建哈弗曼树同自底向上,编码时用weight标识访问状态即可。

注意

  • cdlen在输出的时候不可以加一

代码

#include<algorithm>
#include<cstring>
using namespace std;

struct HTNode{
	int lchild,rchild,parent;
	int weight;
};
const int maxn=101;
int w[maxn];
int n;

void select(HTNode *HT,int n,int& s1,int &s2){
	int m=0xfffffff;
	for(int i=1;i<=n;i++){
		if(HT[i].weight<m&&HT[i].parent==0){
			s1=i;
			m=HT[i].weight;
		}
	}
	m=0xfffffff;
	for(int i=1;i<=n;i++){
		if(HT[i].weight<m&&HT[i].parent==0&&i!=s1){
			s2=i;
			m=HT[i].weight;
		}
	}
	if(s1>s2) swap(s1,s2);
}

void HuffmanCoding(HTNode *HT,char **&HC,int w[],int n){
	if(n<=1) return;
	int m=2*n-1;
	int s1,s2;
	HT=new HTNode[m+1];
	for(int i=1;i<=n;i++){           
		HT[i].parent=HT[i].lchild=HT[i].rchild=0;
		HT[i].weight=w[i];
	}
	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);
		HT[i].weight=HT[s1].weight+HT[s2].weight;
		HT[s1].parent=HT[s2].parent=i;
		HT[i].lchild=s1;
		HT[i].rchild=s2;
	}
	HC=new char*[n+1];
	char *cd=new char[n];                                
	int c=m;  //m为父节点 
	int cdlen=0;
	for(int i=1;i<=m;i++){ //作为访问标志 
		HT[i].weight=0;         
	} 
	while(c){ //回归根节点,根节点左右子树都访问后的父节点为0,结束循环 
		if(HT[c].weight==0){
			HT[c].weight=1;
			if(HT[c].lchild!=0){
				c=HT[c].lchild;
				cd[cdlen++]='0';
			}
			else if(HT[c].rchild==0){
				cd[cdlen]='\0'; //cdlen不能加一,因为退回是退到父节点,消除的是边,'\0'不代表边 
				HC[c]=new char[cdlen+1]; //c为当前叶节点 
				strcpy(HC[c],cd);
			}
		}
		else if(HT[c].weight==1){
			HT[c].weight=2;
			if(HT[c].rchild!=0){
				c=HT[c].rchild;
				cd[cdlen++]='1';
			}
		} 
		else {
			HT[c].weight=0;
			c=HT[c].parent;
			--cdlen;
		}
	} 
}

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;
}