#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 SIR1(ALGraph* G,int a,double inf,double rec,char* str) //传入的分别为网络,感染节点,感染率,恢复率,写入的文件 { double rate;//传入节点作为感染节点的感染规模 int i=0; int sum=0;//统计100次传播后的结果 FILE* fp; fp=fopen(str,"at"); //所有节点最开始为易感态 for(int k=0;k<100;k++) { int Inf[G->vexnum]; int newInf[G->vexnum]; int recnum=0;//统计传播结束后,处于恢复状态的节点个数 for(i=0;i<G->vexnum;i++) { G->adjlist[i].nodeState=0; } //给感染节点赋值 G->adjlist[a].nodeState=1;//传入的j节点a为感染态 //把感染节点交给数组 Inf[0]=a; double infection=inf;//感染概率 int count=1;//当前网络中的感染个数 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为周围节点是感染者的个数 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==1) { n++; } s=s->next; } //计算感染率infect_rate infect_rate=1.0-pow(1.0-infection,n); //如果随机数比感染概率小(能感染),且节点状态为易感染,就感染该节点 if(test<=infect_rate&&G->adjlist[nodej].nodeState==0) { newInf[newInfLength]=nodej; G->adjlist[nodej].nodeState=1;//被感染 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;//记录当前新感染的个数,作为继续循环的依据 } for(i=0;i<G->vexnum;i++) { if(G->adjlist[i].nodeState==2) { recnum++; } } sum+=recnum; // //重置所有会节点状态 ,作为下一轮感染准备 // recnum=0; //// Inf[G->vexnum]={0}; //// newInf[G->vexnum]={0}; // for(i=0;i<G->vexnum;i++) // { // G->adjlist[i].nodeState=; // } } rate=(sum*1.0)/(G->vexnum*100); fprintf(fp,"%d %lf %lf ",G->adjlist[a].degree,G->adjlist[a].ec,rate); //重置所有节点的node.state fclose(fp); return; } void SIR(ALGraph *G,char* str,double beta) { //0:易感染 1:感染 2:恢复 double gama=1.0; srand(time( NULL )); int sum_of_recovered; int sum_of_infected; FILE *fp; fp=fopen(str,"w"); for(int node=0;node<G->vexnum;node++) { printf("%d ",node); int sum=0; for(int k=0; k<100; k++) { sum_of_recovered =0; //先把所有节点设置为易感染 for(int i=0; i<G->vexnum; i++) G->adjlist[i].is_infected=0; //最初那个节点设置为感染 G->adjlist[node].is_infected=1; sum_of_infected=1; //下面的while中一轮一轮的把所有节点进行感染 while(1) { //记录所有节点的感染状态 int temp[G->vexnum]; for(int i=0; i<G->vexnum; i++) temp[i]=G->adjlist[i].is_infected; //下面把所有节点进行判断是否感染或易感 for(int i=0; i<G->vexnum; i++) { if(G->adjlist[i].is_infected==0) { EdgeNode *p; p=G->adjlist[i].firstedge; int count=0;//统计易感旁边感染的个数,用于计算感染的概率 while(p!=NULL) { if(temp[p->adjvex]==1) count++; p=p->next; } double infect_rate=1-pow(1.0-beta,count); if(rand()/(double)RAND_MAX<=infect_rate) { G->adjlist[i].is_infected=1; sum_of_infected++; } } else if(G->adjlist[i].is_infected==1) { if(rand()/(double)RAND_MAX<=gama) { G->adjlist[i].is_infected=2; sum_of_infected--; sum_of_recovered++; } } } if(sum_of_infected==0) break; } sum+=sum_of_recovered; } double rate=(sum*1.0)/(G->vexnum*100.0); fprintf(fp,"%d %lf %lf ",G->adjlist[node].degree,G->adjlist[node].ec,rate); } fclose(fp); } void DoubleNetworkSIR(ALGraph *G1,ALGraph* G2,ALGraph* G3,char* str,double beta1,double beta2) { //传入参数依次为(网络G1.连接边G2,网络G3,写入的文件,G1中的传播率,G2中的传播率) //0:易感染 1:感染 2:恢复 double gama=1.0; srand(time( NULL )); int sum_of_recovered; int sum_of_infected; FILE *fp; fp=fopen(str,"w"); for(int node=0;node<(G1->vexnum+G3->vexnum);node++) { printf("%d ",node); int sum=0; for(int k=0; k<100; k++) { sum_of_recovered =0; //先把所有节点设置为易感染 for(int i=0; i<G1->vexnum; i++) G1->adjlist[i].is_infected=0; for(int i=0; i<G3->vexnum; i++) G3->adjlist[i].is_infected=0; //最初那个节点设置为感染(需要区分两个不同的网络) if(node<G1->vexnum) G1->adjlist[node].is_infected=1; else G3->adjlist[node-(G1->vexnum)].is_infected=1; sum_of_infected=1; //下面的while中一轮一轮的把所有节点进行感染 while(1) { //记录所有节点的感染状态 int temp1[G1->vexnum];//G1中的感染点 int temp2[G3->vexnum];//G3中的感染点 for(int i=0; i<G1->vexnum; i++) temp1[i]=G1->adjlist[i].is_infected; for(int i=0; i<G3->vexnum; i++) temp2[i]=G3->adjlist[i].is_infected; //下面把所有节点进行判断是否感染或易感 //G1中的点 for(int i=0; i<G1->vexnum; i++) { if(G1->adjlist[i].is_infected==0) { EdgeNode *p; p=G1->adjlist[i].firstedge; int count1=0;//统计易感旁边感染的个数,用于计算感染的概率 (先统计自己网络的,再统计相连接网络的) ,这里为G1中的邻居 int count2=0;//统计G3中的邻居 while(p!=NULL) { if(temp1[p->adjvex]==1) count1++; p=p->next; } //需要判断这个点是否与G3中的点相连(根据这个点是否在G2判断) EdgeNode *s; s=G2->adjlist[i].firstedge; //如果相连,看相连G3中的点是否感染 while(s!=NULL) { if(temp2[s->adjvex]==1) count2++; s=s->next; } double infect_rate=1-pow(1.0-beta1,count1)*pow(1.0-beta2,count2); if(rand()/(double)RAND_MAX<=infect_rate) { G1->adjlist[i].is_infected=1; sum_of_infected++; } } else if(G1->adjlist[i].is_infected==1) { if(rand()/(double)RAND_MAX<=gama) { G1->adjlist[i].is_infected=2; sum_of_infected--; sum_of_recovered++; } } } //G3中的点 for(int i=0; i<G3->vexnum; i++) { if(G3->adjlist[i].is_infected==0) { EdgeNode *p; p=G3->adjlist[i].firstedge; int count1=0;//统计易感旁边感染的个数,用于计算感染的概率 int count2=0;//统计G3的邻居 while(p!=NULL) { if(temp2[p->adjvex]==1) count2++; p=p->next; } //需要判断这个点是否与G3中的点相连(根据这个点是否在G2判断) EdgeNode *s; s=G2->adjlist[i].firstedge; //如果相连,看相连G3中的点是否感染 while(s!=NULL) { if(temp1[s->adjvex]==1) count1++; s=s->next; } double infect_rate=1-pow(1.0-beta1,count1)*pow(1.0-beta2,count2); if(rand()/(double)RAND_MAX<=infect_rate) { G3->adjlist[i].is_infected=1; sum_of_infected++; } } else if(G3->adjlist[i].is_infected==1) { if(rand()/(double)RAND_MAX<=gama) { G3->adjlist[i].is_infected=2; sum_of_infected--; sum_of_recovered++; } } } if(sum_of_infected==0) break; } sum+=sum_of_recovered; } double rate=(sum*1.0)/((G1->vexnum+G3->vexnum)*100.0); if(node<G1->vexnum) fprintf(fp,"%d %lf %lf ",G1->adjlist[node].degree,G1->adjlist[node].ec,rate); else fprintf(fp,"%d %lf %lf ",G3->adjlist[node-(G1->vexnum)].degree,G3->adjlist[node-(G1->vexnum)].ec,rate); } fclose(fp); } //创建连接的边,并写入文件 void createLink(char* str) { FILE* fp; fp=fopen(str,"w"); srand((unsigned)time(NULL)); for (int i=0;i<2000;i++) { fprintf(fp,"%d %d ",rand()%2000,rand()%2000); //fpintf(fp,"%d %d",rand()%2000,rand()%2000); } fclose(fp); } int main() { char* str1="E:\data_set\netsci1.txt";//G1,网络 char* str2="E:\data_set\netsci2.txt";//G2,连边 char* str3="E:\data_set\netsci3.txt";//G3,网络 createLink(str2);//创建连边 //G1、G3为两个网络,G2为他们的连接 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(G3,2); //计算特征向量中心性 eigenvector_centrality(G1); eigenvector_centrality(G3); //SIR,此处为单个节点推动 char* str4="E:\data_set\result.txt"; //{ //printf("%d ",i); //SIR1(G1,i,0.08,1,str4); //} //SIR(G1,str4,0.08); DoubleNetworkSIR(G1,G2,G3,str4,0.15,0.1); return 0; }