void SIR(ALGraph* G,int a,double inf,double rec,char* str) //传入的分别为网络,感染节点,感染率,恢复率,写入的文件 { double rate;//传入节点作为感染节点的感染规模 int infTatal=1;//感染节点总数 int Inf[G->vexnum]; int newInf[G->vexnum]; int i=0; FILE* fp; fp=fopen(str,"at"); //给感染数组赋初值 for(i=0;i<infTatal;i++) { Inf[i]=a; G->adjlist[i].nodeState=0;//传入的数组为感染态 } for(i=0;i<infTatal;i++) { newInf[i]=0; } double infection=inf;//感染概率 int count=infTatal;//当前网络中的感染个数 srand((unsigned)time(NULL)); //设置种子,用于随机数产生 while(count>0)//还能继续感染 { int newInfLength=0;//表示新感染节点的个数 for(i=0;i<count;i++) { int vert=Inf[i];//当前的感染点 EdgeNode* p; p=G->adjlist[vert].firstedge; //用当前节点去感染其他节点 while(p!=NULL) { int n=0; double infect_rate;//感染的概率为1-(1-λ)^n;其中n为感染率,n为周围节点是感染者的个数 double test=rand()/(double)RAND_MAX;//rand()产生随机数为[1,32767],RAND_MAX设置为32767,那么test范围[0.1] ; //计算n int nodej=p->adjvex;//记录当前连接的节点 //用s查看当前连接节点的周围有多少感染者 EdgeNode* s=G->adjlist[nodej].firstedge; while(s!=NULL) { if(G->adjlist[s->adjvex].nodeState==0) { n++; } s=s->next; } //计算感染率infect_rate infect_rate=1.0-pow(1.0-infection,n); //如果随机数比感染概率小(能感染),且节点状态为易感染,就感染该节点 if(test<=infect_rate&&G->adjlist[nodej].nodeState==1) { newInf[newInfLength]=nodej; G->adjlist[nodej].nodeState=0;//被感染 newInfLength++; } p=p->next; } } //感染节点恢复(不包括上一步新感染的) for(i=0;i<count;i++) { double recovRate=rec; double test_1=rand()/(double)RAND_MAX;//rand()产生随机数为[1,32767],RAND_MAX设置为32767,那么test范围[0.1] //此处当恢复率设置为1时所有感染节点都能恢复 //恢复分两种情况:1.能恢复,改变nodeState为2;2.不能恢复,放入新感染数组 if(test_1<=recovRate) { G->adjlist[Inf[i]].nodeState=2; } else { newInf[newInfLength]=Inf[i]; newInfLength++; } } //newInf数组中元素两个来源:1.易感染节点被感染;2.感染节点未恢复 //再把新感染的数组newInf交给Inf进行下一次循环 for(i=0;i<newInfLength;i++) { Inf[i]=newInf[i]; } count=newInfLength;//记录当前新感染的个数,作为继续循环的依据 } int recnum=0;//统计传播结束后,处于恢复状态的节点个数 for(i=0;i<G->vexnum;i++) { if(G->adjlist[i].nodeState==2) { recnum++; } } rate=(recnum*1.0)/(G->vexnum); fprintf(fp,"%d %lf %lf ",G->adjlist[a].degree,G->adjlist[a].ec,rate); fclose(fp); return; }
完整代码:(结果写入文件)
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<malloc.h> #include<math.h> #include<time.h> #define MaxVertexNum 90000 #define RAND_MAX 0x7fff //边表节点 typedef struct node { int adjvex; struct node *next; int visit; }EdgeNode; //顶点表节点 typedef struct vnode { int vertex; int KS;//k-core float ec;//特征向量中心性 int is_infected; int nodeState; int is_visit; int layer;//层 int degree;//该节点的度 EdgeNode* firstedge;//指向边表的指针 }VertexNode; typedef VertexNode AdjList[MaxVertexNum]; //图的结构 typedef struct { AdjList adjlist;//顶点表(类似于数组的) int vexnum;//顶点个数 int arcnum;//边个数 }ALGraph; //返回文件行数(网络边数),有换行符" "就为一行 int lines(char* str) { int c; FILE* fp; int lines=0; fp=fopen(str,"r"); if(fp) { while((c=fgetc(fp))!=EOF) if(c==' ') lines++; fclose(fp); } return lines; } //返回文件最大数(网络节点数) int max(char* str) { FILE* fp; char* p; int line=lines(str); int i=0; int a=0; int b=0; fp=fopen(str,"r"); char buf[1024]; if((fp=fopen(str,"r"))==NULL) { perror("fail to read"); exit(1); } //把文件的内容给buf while(fgets(buf,line,fp)!=NULL) { //p就没有 p=buf; sscanf(p,"%d %d",&a,&b);//输入源为p //i始终为最大的 if(a>i) i=a; if(b>i) i=b; } return i; } //创建图 void createAlgraph(ALGraph* G,char* str) { FILE* fp; int line=lines(str); int node=max(str);//其中最大数 G->vexnum=node+1;//因为是从0开始,所以+1,多了一个0 G->arcnum=line; fp=fopen(str,"r"); char buf[1024]; int len; int m; int n; EdgeNode* s; char* p; int a=0; int b=0; int i=0; char StrLine[1024]; //每个节点的顶点表(vn1(i),vn2(i)) int vn1[line];//这里本来要用vn[line],如果是vc++就不能通过编译,有多少行就有多少(i,j) int vn2[line]; //顶点录入 for(int j=0;j<G->vexnum;j++) { G->adjlist[j].vertex=j; G->adjlist[j].firstedge=NULL; G->adjlist[j].nodeState=1; } if((fp=fopen(str,"r"))==NULL) { perror("faile to read"); exit(1); } while(!feof(fp))//因为行数等于边数,则读取行数个就可以把其他的节点的连接读完 { fgets(StrLine,1024,fp); sscanf(StrLine,"%d%d",&a,&b); vn1[i]=a; vn2[i]=b; i++; } //边节点放入链表 //一行就是一个坐标,有多少行就有多少坐标 for(int k=0;k<line;k++)//有多少行就有多少节点,每个节点对应一个边链 { m=vn1[k],n=vn2[k]; int ii=0; EdgeNode* p; p=G->adjlist[m].firstedge; while(p!=NULL) { if(p->adjvex==n) { ii=1; break; } p=p->next; } if(ii!=1) { s=(EdgeNode*)malloc(sizeof(EdgeNode)); s->adjvex=n;//相连接的顶点 s->next=NULL; s->next=G->adjlist[m].firstedge;//类似于自己写的链表 G->adjlist[m].firstedge=s; //无向图 有来回 s=(EdgeNode*)malloc(sizeof(EdgeNode)); s->adjvex=m; s->next=NULL; s->next=G->adjlist[n].firstedge; G->adjlist[n].firstedge=s; } } //深度为每个节点后面连接的链长度 EdgeNode* q; for( i=0;i<G->vexnum;i++) { int k=0; q=G->adjlist[i].firstedge; while(q!=NULL) { k++; q=q->next; } G->adjlist[i].degree=k; } } //打印邻接表 void printGraph(ALGraph* G) { EdgeNode* s; for(int i=0;i<G->vexnum;i++) { s=G->adjlist[i].firstedge;//s为一个带adjvex,next指针的边表节点 while(s) { printf("(%d,%d)",G->adjlist[i].vertex,s->adjvex); s=s->next; } printf(" "); } } //所属层插入 void insertLayer(ALGraph* G,int layer) { for(int i=0;i<G->vexnum;i++) { G->adjlist[i].layer=layer; } } //打印度中心性 void printDegreeCentrality(ALGraph* G) { for(int i=0;i<G->vexnum;i++) { printf("node %d dgree centrality is:%d ",i,G->adjlist[i].degree); } } //计算特征向量中心性 void eigenvector_centrality(ALGraph *G) { float e[G->vexnum];//记录上一次的指标(最终的特征向量中心性指标 ,因为会把最终的计算赋值给e);下面都用指标代表特征向量指标 float e1[G->vexnum];//记录这一次的指标 float max = 0;//这一次的最大指标 float max1 = 0;//记录上一次最大指标 int flag=0;//当flag=1时,代表找到各个指标 for(int i=0; i<G->vexnum; i++) { e[i]=1;//将每个点初始化为1 e1[i]=0; } EdgeNode *p; p=(EdgeNode*)malloc(sizeof(EdgeNode)); //循环开始 while(flag==0) { max1=max;//max1为上一次的最大值 max=0; for (int i=0; i<G->vexnum; i++) { p=G->adjlist[i].firstedge; while(p!=NULL) { e1[i]+=e[p->adjvex];//第一次的计算结果为他们各自的度 p=p->next; } if(e1[i]>max) max=e1[i];//记录本次的最大指标 } for(int i=0; i<G->vexnum; i++) { if(e[i]!=e1[i]) break; if(i==G->vexnum-1) flag=1;//两次计算结果相同结束循环 } if((1.0/max1-1.0/max)<0.01&&(1.0/max1-1.0/max)>-0.01) flag=1;//当差值较小时也可结束循环 //保留这次的结果到e中,并且将ei重置为0,方便下次计算 for(int i=0; i<G->vexnum; i++) { e[i]=e1[i]; e1[i]=0; } } for(int i=0; i<G->vexnum; i++) { e[i]=e[i]/max; G->adjlist[i].ec=e[i]; } } /* 1.SIR传播模型,改变node.state(0为感染,1为易感染,2为恢复。所有节点初始化为1) 2.SIR函数主要操作感染点,感染点会做两件事:①感染易感节点;②感染节点恢复 3.传播完成的标志为不能再感染新的节点,并返回处于恢复节点的个数 */ void SIR(ALGraph* G,int a,double inf,double rec,char* str) //传入的分别为网络,感染节点,感染率,恢复率,写入的文件 { double rate;//传入节点作为感染节点的感染规模 int infTatal=1;//感染节点总数 int Inf[G->vexnum]; int newInf[G->vexnum]; int i=0; FILE* fp; fp=fopen(str,"at"); //给感染数组赋初值 for(i=0;i<infTatal;i++) { Inf[i]=a; G->adjlist[i].nodeState=0;//传入的数组为感染态 } for(i=0;i<infTatal;i++) { newInf[i]=0; } double infection=inf;//感染概率 int count=infTatal;//当前网络中的感染个数 srand((unsigned)time(NULL)); //设置种子,用于随机数产生 while(count>0)//还能继续感染 { int newInfLength=0;//表示新感染节点的个数 for(i=0;i<count;i++) { int vert=Inf[i];//当前的感染点 EdgeNode* p; p=G->adjlist[vert].firstedge; //用当前节点去感染其他节点 while(p!=NULL) { int n=0; double infect_rate;//感染的概率为1-(1-λ)^n;其中n为感染率,n为周围节点是感染者的个数 double test=rand()/(double)RAND_MAX;//rand()产生随机数为[1,32767],RAND_MAX设置为32767,那么test范围[0.1] ; //计算n int nodej=p->adjvex;//记录当前连接的节点 //用s查看当前连接节点的周围有多少感染者 EdgeNode* s=G->adjlist[nodej].firstedge; while(s!=NULL) { if(G->adjlist[s->adjvex].nodeState==0) { n++; } s=s->next; } //计算感染率infect_rate infect_rate=1.0-pow(1.0-infection,n); //如果随机数比感染概率小(能感染),且节点状态为易感染,就感染该节点 if(test<=infect_rate&&G->adjlist[nodej].nodeState==1) { newInf[newInfLength]=nodej; G->adjlist[nodej].nodeState=0;//被感染 newInfLength++; } p=p->next; } } //感染节点恢复(不包括上一步新感染的) for(i=0;i<count;i++) { double recovRate=rec; double test_1=rand()/(double)RAND_MAX;//rand()产生随机数为[1,32767],RAND_MAX设置为32767,那么test范围[0.1] //此处当恢复率设置为1时所有感染节点都能恢复 //恢复分两种情况:1.能恢复,改变nodeState为2;2.不能恢复,放入新感染数组 if(test_1<=recovRate) { G->adjlist[Inf[i]].nodeState=2; } else { newInf[newInfLength]=Inf[i]; newInfLength++; } } //newInf数组中元素两个来源:1.易感染节点被感染;2.感染节点未恢复 //再把新感染的数组newInf交给Inf进行下一次循环 for(i=0;i<newInfLength;i++) { Inf[i]=newInf[i]; } count=newInfLength;//记录当前新感染的个数,作为继续循环的依据 } int recnum=0;//统计传播结束后,处于恢复状态的节点个数 for(i=0;i<G->vexnum;i++) { if(G->adjlist[i].nodeState==2) { recnum++; } } rate=(recnum*1.0)/(G->vexnum); fprintf(fp,"%d %lf %lf ",G->adjlist[a].degree,G->adjlist[a].ec,rate); fclose(fp); return; } int main() { char* str1="E:\data_set\netsci1.txt"; char* str2="E:\data_set\netsci2.txt"; char* str3="E:\data_set\netsci3.txt"; //G1、G2为两个网络,G3为他们的连接 ALGraph* G1; ALGraph* G2; ALGraph* G3; G1=(ALGraph*)malloc(sizeof(ALGraph)); G2=(ALGraph*)malloc(sizeof(ALGraph)); G3=(ALGraph*)malloc(sizeof(ALGraph)); //创建三个表的信息 createAlgraph(G1,str1);//分别插入图的地址,连接顶点信息 createAlgraph(G2,str2); createAlgraph(G3,str3); //插入层数 insertLayer(G1,1); insertLayer(G2,2); //计算特征向量中心性 eigenvector_centrality(G1); int a[1]={3}; int arrayLenth=sizeof(a)/sizeof(int); //SIR,此处为单个节点推动 char* str4="E:\data_set\result.txt"; for(int i=0;i<G1->vexnum;i++) { SIR(G1,i,0.2,1,str4); } return 0; }
运行结果:
总共有2000条数据,对应2000个节点