C言語:階層的クラスタリング、階層的クラスター分析(完)
とりあえず完成しましたが読むに値しないコードです。やっぱりコードを描く上で難しいのが変数の名前と注釈だと思います。とりあえず、仕様は前の記事の通りになりました。
これから、たくさんのコードを描いていきたいと思います。
以下コードです。
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.h> #define MAX 1000 //------------ struct data -------------- struct dataline{ double data; struct dataline *next; }; struct clust{ int num; double length; struct dataline *vec; struct clust *right; struct clust *left; }; struct line{ int point; struct line *next; }; struct intmat{ struct dataline *intlist; struct intmat *next; }; //------------ define function ------------ struct clust *clustalloc(void); struct line *linealloc(void); struct clust *makeclust(struct clust **root,int i,int j,double length,int num); double length(struct clust *c1,struct clust *c2); void printclust(struct clust *root); void append(struct line *end,int point); void del(struct line *head,int point); struct dataline *makevec(struct dataline *list1,struct dataline *list2); struct dataline *intsplit(char *s1,int *num); struct dataline *intalloc(void); struct intmat *matalloc(void); struct intmat *readdata(int argc,char *argv[],int *datalength); double pointlength(struct dataline *list1,struct dataline *list2); //------------------------------ int main(int argc,char *argv[]){ int num=0,i,datalength; struct clust *mat[MAX],*root,*head,*newc; struct line *lp,*rootline,*headline,*end,*lp2,*lp3,*start,*p; struct intmat *data,*headmat,*matp; struct dataline *pline; double min,d; int minpair[2]; root=clustalloc(); rootline=linealloc(); headline=NULL; data=readdata(argc,argv,&datalength); matp=data; i=0; while(matp!=NULL){ pline=matp->intlist; while(pline!=NULL){ pline=pline->next; } matp=matp->next; i++; } matp=data; for(num=0;num<argc-1;num++){ pline=matp->intlist; mat[num]=clustalloc(); mat[num]->num=num; mat[num]->length=0; mat[num]->vec=matp->intlist; mat[num]->right=mat[num]->left=NULL; lp=linealloc(); lp->next=headline; lp->point=num; headline=lp; while(pline!=NULL){ pline=pline->next; } matp=matp->next; } end=lp; while(lp!=NULL){ lp=lp->next; } lp=end; while(lp->next->next!=NULL){ min=pointlength(mat[lp->point]->vec,mat[lp->next->point]->vec); minpair[0]=lp->point; minpair[1]=lp->next->point; lp2=lp; while(lp2!=NULL){ lp3=lp2->next; while(lp3!=NULL){ d=pointlength(mat[lp2->point]->vec,mat[lp3->point]->vec); if(d<=min){ minpair[0]=lp2->point; minpair[1]=lp3->point; newc=makeclust(mat,minpair[0],minpair[1],d,num); min=d; } lp3=lp3->next; } lp2=lp2->next; } p=end; del(lp,minpair[0]); del(lp,minpair[1]); append(lp,num); mat[num]=newc; num++; } p=end; root=makeclust(mat,p->point,p->next->point,pointlength(mat[p->point]->vec,mat[p->next->point]->vec),num); printclust(root); while(p!=NULL){ p=p->next; } return 0; } //--------------------- void printclust(struct clust *root){ static int num=0; int i; struct clust *p; p=root; printf("%d:%lf\n",p->num,p->length); if(p->right!=NULL){ for(i=0;i<num;i++)printf(" "); printf("right->"); printclust(p->right); num++; } if(p->left!=NULL){ for(i=0;i<num;i++)printf(" "); printf("left->"); printclust(p->left); num++; } return; } void append(struct line *end,int point) { struct line *lp,*new,*lp2; new=linealloc(); new->point=point; lp=end; while(lp!=NULL){ lp2=lp; lp=lp->next; } lp2->next=new; } void del(struct line *head,int point){ struct line *p,*end,*old,*tp,*p2,*p3; p=head; while(p!=NULL){ if(p->point==point){ if(p==head){ p2=head; while(p2->next!=NULL){ p2->point=p2->next->point; p3=p2; p2=p2->next; } free(p3->next); p3->next=NULL; return ; } end=old->next; old->next=end->next; return; } old=p; p=p->next; } } struct clust *makeclust(struct clust **root,int i,int j,double length,int num){ struct clust *newclust; newclust=clustalloc(); newclust->num=num; newclust->right=root[i]; newclust->left=root[j]; newclust->vec=makevec(root[i]->vec,root[j]->vec); newclust->length=length; return newclust; } struct intmat *readdata(int argc,char *argv[],int *datalength) { struct intmat *data,*matp,*head; struct dataline *line,*p; int i; FILE *rfp; char buf[256]; head=NULL; printf("read:"); for(i=1;i<argc;i++){ printf("%s ",argv[i]); if((rfp=fopen(argv[i],"r"))==NULL){ printf("%s is not readable\n",argv[i]); exit(1); } while(fgets(buf,256,rfp)!=NULL) line=intsplit(buf,datalength); p=line; data=matalloc(); data->next=head; data->intlist=line; head=data; } puts(""); return data; } double pointlength(struct dataline *list1,struct dataline *list2) { double out=0; struct dataline *p1,*p2; p1=list1; p2=list2; while(p1!=NULL){ out+=pow((p1->data-p2->data),2); p1=p1->next; p2=p2->next; } return sqrt(out); } void split(char *s1){ char *temp; char *s2=" "; temp=strtok(s1,s2); while(temp!=NULL){ printf("%s\n",temp); temp=strtok(NULL,s2); } } struct dataline *intsplit(char *s1,int *num){ char *temp; char *s2=" "; int i; int j=0; struct dataline *p,*head; temp=strtok(s1,s2); head=NULL; while(temp!=NULL){ i=atoi(temp); temp=strtok(NULL,s2); p=intalloc(); p->next=head; p->data=i; head=p; j++; } *num=j; return p; } struct dataline *makevec(struct dataline *list1,struct dataline *list2){ struct dataline *out,*p,*p2,*head; p=list1; p2=list2; head=NULL; while(p!=NULL){ out=intalloc(); out->data=(p->data+p2->data)/2; out->next=head; head=out; p=p->next; p2=p2->next; } return head; } //-----memory allocate--------------------------------------- struct dataline *intalloc(void) { return (struct dataline *)malloc(sizeof(struct dataline)); } struct intmat *matalloc(void) { return (struct intmat *)malloc(sizeof(struct intmat)); } struct clust *clustalloc(void) { return (struct clust *)malloc(sizeof(struct clust)); } struct line *linealloc(void) { return (struct line *)malloc(sizeof(struct line)); }