九度OJ-1172-哈夫曼树
http://ac.jobdu.com/problem.php?pid=1172
哈夫曼树(Huffman tree):给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,即哈夫曼树
这题可以建树,也可以不建树。
建树:
#include<stdio.h> #include<string.h> #include<stdlib.h> #define maxvalue 0x7fffffff struct huffman { int weight; int parent,lchild,rchild; }list[5000]; int main() { int n,m; int i,j; int ans; int x1,x2; int m1,m2; while(scanf("%d",&n)!=EOF) { m=2*n-1; for(i=0;i<m;i++) list[i].parent=list[i].lchild=list[i].rchild=-1; for(i=0;i<n;i++) scanf("%d",&list[i].weight); ans=0; for(i=0;i<n-1;i++) { x1=x2=0; m1=m2=maxvalue; for(j=0;j<n+i;j++) { if(list[j].weight<m1&&list[j].parent==-1) { x2=x1; m2=m1; x1=j; m1=list[j].weight; } else if(list[j].weight<m2&&list[j].parent==-1) { x2=j; m2=list[j].weight; } } list[x1].parent=n+i; list[x2].parent=n+i; list[n+i].lchild=x1; list[n+i].rchild=x2; list[n+i].weight=list[x1].weight+list[x2].weight; ans+=list[n+i].weight; } printf("%d\n",ans); } return 0; }
不建树的简单一点:
#include<stdio.h> #include<string.h> #include<stdlib.h> int cmp(const void *a,const void *b) { return *(int *)a-*(int *)b; } int main() { int n,i,ans; int a[5000]; while(scanf("%d",&n)!=EOF) { for(i=0;i<n;i++) scanf("%d",&a[i]); ans=0; for(i=0;i<n-1;i++) { qsort(a+i,n-i,sizeof(a[0]),cmp); ans+=(a[i]+a[i+1]); a[i+1]+=a[i]; } printf("%d\n",ans); } return 0; }
依据字符出现概率,可以利用哈夫曼树构造哈夫曼编码,写了个简易的代码:
给出26个字母的频度,执行哈夫曼编码,输入1编码,输入2译码。
#include<stdio.h> #include<string.h> #include<stdlib.h> #define maxvalue 0x7fffffff struct cam1 { char c; char s[50]; int len; }zimu[30]; struct cam2 { int weight; int parent,lchild,rchild; }list[60]; void init() { int i; for(i=0;i<26;i++) zimu[i].c='a'+i; } void huffmantree() { int i,j; int x1,x2; int m1,m2; int pindu[26]={64,13,22,32,103,21,15,47,57,1,2,32,20,57,63,15,1,48,51,80,23,8,18,1,16,1}; //26个字母的频度 for(i=0;i<60;i++) list[i].parent=list[i].lchild=list[i].rchild=-1; for(i=0;i<26;i++) list[i].weight=pindu[i]; for(i=0;i<25;i++) { x1=x2=0; m1=m2=maxvalue; for(j=0;j<26+i;j++) { if(list[j].weight<m1&&list[j].parent==-1) { x2=x1; m2=m1; x1=j; m1=list[j].weight; } else if(list[j].weight<m2&&list[j].parent==-1) { x2=j; m2=list[j].weight; } } list[26+i].lchild=x1; list[26+i].rchild=x2; list[x1].parent=list[x2].parent=26+i; list[26+i].weight=list[x1].weight+list[x2].weight; } } void huffmanbianma() { int i,j,start; char s[100]; int p,c,k; for(i=0;i<26;i++) { memset(s,0,sizeof(s)); start=40; c=i; p=list[c].parent; while(p!=-1) { if(list[p].lchild==c) s[start]='0'; else s[start]='1'; start--; c=p; p=list[c].parent; } for(k=0,j=start+1;j<=40;k++,j++) zimu[i].s[k]=s[j]; zimu[i].s[k]='\0'; zimu[i].len=k; } printf("26个字母的哈夫曼编码如下:\n"); for(i=0;i<26;i++) printf("%c----->%s\n",'a'+i,zimu[i].s); } int main() { int i,j; int ans,len; char str[1000]; int k1,k2,flag; printf("Welcome to Cambridgeacm\n"); init(); huffmantree(); huffmanbianma(); printf("输入1时执行编码\n"); printf("输入2时执行译码\n"); while(scanf("%d",&ans)!=EOF) { switch(ans) { case 1: { printf("请输入一段字符串\n"); scanf("%s",str); len=strlen(str); for(i=0;i<len;i++) printf("%s",zimu[str[i]-'a'].s); printf("\n"); printf("编码结束\n"); } case 2: { printf("请输入一段01代码\n"); scanf("%s",str); len=strlen(str); for(i=0;i<len;i++) { for(j=0;j<26;j++) { flag=1; for(k1=i,k2=0;k1<=i+zimu[j].len-1&&str[k1]!='\0';k1++,k2++) if(str[k1]!=zimu[j].s[k2]) { flag=0; break; } if(flag) { printf("%c",zimu[j].c); i+=(zimu[j].len-1); break; } } } printf("\n"); printf("译码结束\n"); } } } return 0; }