Attractor算法代码整理

来源:互联网 发布:大数据教程视频 编辑:程序博客网 时间:2024/05/22 16:59


  1. 建立节点表
  2. 建立边表
  3. 建立节点边表
  4. 交互
  5. 社区发现

1-3为交互做准备

一、建立节点表

EstablishNodeTable(argv[1], ator(argv[3]));

参数:

argv[1]: 表示输入的数据集文件名
ator(argv[3])): 表示数据集边的数量,ator将字符串转为整型数

打开数据集文件

FILE * file = fopen(inputfilename, "r");

对于每个节点i,初始其邻居节点数量为0

int NeighborNumber[NetNodeNum];for(int i = 0; i < NetNodeNum; i++)    NeighborNumber[i] = 0;

求每个节点的邻居节点数,用于为指针申请合适空间内存

for(int i=0; i<FileLine; i++)    fscanf(file,"%d %d", &node_1, &node_2);    NeighborNumber[node_1-1]++;    NeighborNumber[node_2-1]++;

建立节点表

for(int i=0; i<FileLine; i++)    fscanf(file,"%d %d", &node_1, &node_2);    NodeTable[node_1-1].Pointer[NodeTable[Node_1-1].NodeNum++]=node_2;    NodeTable[node_2-1].Pointer[NodeTable[Node_2-1].NodeNum++]=node_1;

为每个节点的邻居节点排序(升序)

SortFun(NodeTable[i].Pointer, NodeTable[i].NodeNum);void SortFun(int *Pointer, int Num) 

采用冒泡排序算法,但设置了“最后改变位置”来确定是否排序完毕

所建节点表如图:
节点表

二、建立边表

EstablishEdgeTable();

求每个节点的边数(每边只保存一次)

for(int loop_i=0; loop_i<NetNodeNum; loop_i++)    EdgeNumber[loop_i]=0;    for(int loop_j=0; loop_j<NodeTable[Loop_i].NodeNum; loop_j++)        if(NodeTable[loop_i].Pointer[loop_j]>loop_i+1)            EdgeNumber[Loop_i]++;

建立边表

int edgeid = 0; //网络总的边数for(int loop_i=0; loop_i<NetNodeNum; loop_i++){    int edge_loc_tmp=0;//边表中每个节点的边的下标    for(int loop_j=0; loop_j<NodeTable[loop_i].NodeNum;loop_j++)    {        if(NodeTable[loop_i].Pointer[loop_j]>loop_i+1)        {            EdgeWithAttachmentTable[loop_i].Pointer[edge_loc_tmp].n_1_ID=loop_i+1;         EdgeWithAttachmentTable[loop_i].Pointer[edge_loc_tmp].n_2_ID=NodeTable[loop_i].Pointer[loop_j];                       EdgeWithAttachmentTable[loop_i].Pointer[edge_loc_tmp].e_ID=edgeid;            edge_loc_tmp++;        }    }}

所建边表如图:
边表

发现两个节点的共同邻居,以及各自的独有邻居

void FindNeighbors(int node_1, int node_j){    //变量    int num1=NodeTable[node_i-1].NodeNum;//邻居总数    int *A1=NodeTable[node_i-1].Pointer; //指向node_i的邻接表的指针    int num2=NodeTable[node_j-1].NodeNum;    int *A2=NodeTable[node_j-1].Pointer;    int p1_loc=0;//表示node_1节点的邻接表下标    int p2_loc=0;    int *p1=&A1[0];//p1指向node_i的第一个邻节点    int *p2=&A2[0];    int cn_length=0;//共同邻居(邻域)的长度    int diffa_length=0;//node_i独有邻居的长度    int diffb_length=0;    int cn_loc=1;//邻域地址下标,从1开始,0用于保存长度大小    int diffa_loc=1;    int diffb_loc=1;    while(p1_loc<num1 && p2_loc<num2)     {        if(A1[p1_loc]<A2[p2_loc])        {            if(A1[p1_loc]!=node_j)            {                DiffA[diffa_loc]=A1[p1_loc];                diffa_length++;                diffa_loc++;                p1_loc++;            }            else                p1_loc++;        }//求node_i的独有邻居

效果如图:
节点1独有邻居

        else if(A1[p1_loc]==A2[p2_loc])        {            CN[cn_loc]=A1[p1_loc];            cn_length++;            cn_loc++;            p1_loc++;            p2_loc++;        }//求共同邻居

效果如图:
共同邻居

        else        {            if(A2[p2_loc]!=node_i)            {                DiffB[diffb_loc]=A2[p2_loc];                diffb_length++;                diffb_loc++;                p2_loc++;            }            else                 p2_loc++;        }//求node_j的独有邻居    }}

求剩余独有邻居

    if(p1_loc==num1)    {        while(p2_loc<num2)        {            if(A2[p2_loc]!=node_i)            {                DiffB[diffb_loc]=A2[p2_loc];                diffb_length++;                diffb_loc++;                p2_loc++;            }            else                p2_loc++;        }//p2_loc余下节点为node_j的独有邻居(node_i除外)    }    else     {        while(p1_loc<num1)        {            if(A1[p1_loc]!=node_j)            {                DiffA[diffa_loc]=A1[p1_loc];                diffa_length++;                diffa_loc++;                p1_loc++;            }            else                p1_loc++;        }    }//p1_loc余下节点为node_i的独有邻居(node_j除外)

保存邻居长度

CN[0]=cn_length;DiffA[0]=diffa_length;DiffB[0]=diffb_length;

计算每条边的杰卡德距离

    EdgeWithAttachmentTable[i].Pointer[j].dist=1.0-(double)(CN[0]+2)/(double)(CN[0]+DiffA[0]+DiffB[0]+2);

2为边的两端节点

杰卡德距离公式:
杰卡德距离

建立共同邻居的四列二维矩阵,如图:

共同邻居矩阵

    //对于边表中第i个节点的第j条边    for(int s=1; s<=CN[0];s++)    {        int NodeCN=CN[s];        int Loc_Node_1_R=-1;//node_1和node_CN中最小节点对于id        int Loc_Node_1_C=-1;//边(node_1,node_CN)对应id(相对于最小节点)        int Loc_Node_2_R=-1;        int Loc_Node_2_C=-1;        int NodeMin=(node_1<NodeCN)?node_1:NodeCN;        int NodeMax=(node_1>NodeCN)?node_1:NodeCN;        //求最小节点对应id        Loc_Node_1_R=NodeMin-1;        //求边所在id        for(int loop=0;loop<EdgeWithAttachmentTable[NodeMin-1].EdgeNum;loop++)            if(EdgeWithAttachmentTable[NodeMin-1].Pointer[loop].n_2_ID==NodeMax)            {                Loc_Node_1_C=loop;                break;            }    //同理求Loc_Node_2_R, Loc_Node_2_C

构建二维矩阵

    EdgeWithAttachmentTable[i].Pointer[j].CN_Loc[4*(s-1)+0)=Loc_Node_1_R;    EdgeWithAttachmentTable[i].Pointer[j].CN_Loc[4*(s-1)+1)=Loc_Node_1_C;    EdgeWithAttachmentTable[i].Pointer[j].CN_Loc[4*(s-1)+2)=Loc_Node_2_R;    EdgeWithAttachmentTable[i].Pointer[j].CN_Loc[4*(s-1)+3)=Loc_Node_2_C;

构建node_1独有邻居信息表,如图
独有邻居信息表

    //对于边表中第i个节点的第j条边    int Edgenum_tmp=0;//保存边(DiffA,node_2)的共同邻居总长度    for(int s=1;s<=DiffA[0];s++)    {        int Node_N_1=DiffA[s];        //求边(node_N_1,node_2)的共同邻居        FindCN(Node_N_1, node_2);        //此时,CN[0]表示Node_N_1和node_2的共同邻居长度        //求边(DiffA[s],node_2)的共同邻居总长度        Edgenum_tmp=Edgenum_tmp+CN[0];        EdgeWithAttachmentTable[i].Pointer[j].N_1_Info[4*(s-1)+0]=Node_N_1;        EdgeWithAttachmentTable[i].Pointer[j].N_1_Info[4*(s-1)+1]=CN[0];        //下述求边表中对应行列值的方法同上述共同邻居矩阵表        EdgeWithAttachmentTable[i].Pointer[j].N_1_Info[4*(s-1)+2]=NodeMin-1;        EdgeWithAttachmentTable[i].Pointer[j].N_1_Info[4*(s-1)+3]=loop;    }

构建(DiffA, 其与Node2共同邻居)信息表,如图:
独有共同邻居信息表

Edgenum_tmp=0;for(int s=1;s<=DiffA[0];s++){    int Node_N_1=DiffA[1];    FindCN(Node_N_1,node_2);    //CN[0]表示Node_N_1和node_2的共同邻居长度    for(int ss=1;ss<=CN[0];ss++)    {        int NodeCN=CN[ss];        int Loc_Node_N_1_R=-1;//(Node_N_1,NodeCN)所在行        int Loc_Node_N_1_C=-1;//所在列        int Loc_Node_2_R=-1;        int Loc_Node_2_C=-1;        EdgeWithAttachmentTable[i].Pointer[j].N_1_Loc[4*Edgenum_tmp+0]=Loc_Node_N_1_R;          EdgeWithAttachmentTable[i].Pointer[j].N_1_Loc[4*Edgenum_tmp+1]=Loc_Node_N_1_C;        EdgeWithAttachmentTable[i].Pointer[j].N_1_Loc[4*Edgenum_tmp+2]=Loc_Node_2_R;                EdgeWithAttachmentTable[i].Pointer[j].N_1_Loc[4*Edgenum_tmp+3]=Loc_Node_2_C;

三、建立节点边表

EstablishEdgesOfNodeTable();

构建节点边表

for(int i=0;i<NetNodeNum;i++)    for(int j=0;j<EdgeWithAttachmentTable[i].EdgeNum;j++)    {        int node_1=EdgeWithAttachmentTable[i].Pointer[j].n_1_ID;        int node_2=EdgeWithAttachmentTable[i].Pointer[j].n_2_ID;        EdgesOfNodeTable[node_1_1].Pointer[EdgesOfNodeTable[node_1-1].EdgeNum].Row=i;        EdgesOfNodeTable[node_1-1].Pointer[EdgesOfNodeTable[node_1-1].EdgeNum].Column=j;        EdgesOfNodeTable[node_1-1].EdgeNum++;        EdgesOfNodeTable[node_2-1].Pointer[EdgesOfNodeTable[node_2-1].EdgeNum].Row=i;        EdgesOfNodeTable[node_2-1].Pointer[EdgesOfNodeTable[node_2-1].EdgeNUm].Column=j;        EdgesOfNodeTable[node_2-1].EdgeNum++;

效果如图:
节点边表

四、交互

Interaction(BETA, atoi(argv[3]));

边的距离

    double D[NetEdgeNum];//边的距离    int EdgeLocCount=0;//边的下标    for(int s_1=0;s_1<NetNodeNum;s_1++)        for(int s_2=0;s_2<EdgeWithAttachmentTable[s_1].EdgeNum;s_2++)            D[EdgeLocCount++]=EdgeWithAttachmentTable[s_1].Pointer[s_2].dist;

开始交互

int Terminate=1;//终止条件int Loop=0;//迭代次数while(Terminate){    Loop++;    for(int s_1=0;s_1<NetNodeNum;s_1++)        for(int s_2=0;s_2<EdgeWithAttachmentTable[s_1].EdgeNum;s_2++)            if(EdgeWithAttachmentTable[s_1].Pointer[s_2].dist>0 && EdgeWithAttachmentTable[s_1].Pointer[s_2].dist<1)            {                EA ThisEA=EdgeWithAttachmentTable[s_1].Pointer[s_2];                int ThisNode_1=ThisEA.n_1_ID;                int ThisNode_2=ThisEA.n_2_ID;                int ThisEdgeId=ThisEA.e_ID;//在总边数中id                double CI=0.0;//共同邻居的影响                double N_1_I=0.0;//node_1的独有邻居影响                double N_2_I-0.0;//node_2的独有邻居影响

共同邻居影响

    for(int s_3=0;s_3<ThisEA.CN_Loc_Length;s_3++)    {        double Distance_CI_1;//节点1和共同邻居节点间的距离        double Distance_CI_2;//节点2和共同邻居节点间的距离        int *CNLocTmp=ThisEA.CN_Loc;//共同邻居表        Distance_CI_1=EdgeWithAttachmentTable[CNLocTmp[s_3*4+0]].Pointer[CNLocTmp[s_3*4+1]].dist;        Distance_CI_2=EdgeWithAttachmentTable[CNLocTmp[s_3*4+2]].Pointer[CNLocTmp[s_3*4+3]].dist;        int CNTmp_1=EdgeWithAttachmentTable[CNLocTmp[s_3*4+0].Pointer[CNLocTmp[s_3*4+1].n_1_ID;        int CNTmp_2=EdgeWithAttachmentTable[CNLocTmp[s_3*4+0].Pointer[CNLocTmp[s_3*4+1].n_2_ID;        int CNTmp_3=(CNTmp_1==ThisNode_1)?CNTmp_2:CNTmp_1;//表示邻居节点        CI=CI+((double)(1-Distance_CI_2)/(double)NodeTable[ThisNode_1-1].NodeNum)*sin(1-Distance_CI_1);        CI=CI+((double)(1-Distance_CI_1)/(double)NodeTable[ThisNode_2-1].NodeNum)*sin(1-Distance_CI_2);    }

说明图:
共同邻居说明图

共同邻居影响CI公式:
CI

节点1独有邻居影响——求lambda

    int s_3=0;    int s_4=0;//节点1的所有独有邻居与节点2的共同邻居下标    int s_4_count;//当前独有邻居与节点2的共同邻居下标    while(s_3<ThisEA.N_1_Info_Length)//节点1的独有邻居长度    {        int Ngh_N_1=ThisEA.N_1_Info[s_3*4+0];//节点1独有邻居        int CN_Num=ThisEA.N_1_Info[s_3*4+1];//Node_N_1和node2的共同邻居长度        double Distance_N_N_1=EdgeWithAttachmentTable[ThisEA.N_1_Info[s_3*4+2]].Pointer[ThisEA.N_1_Info[s_3*4+3]].dist;        s_4_count=s_4;        double lambda_numerator=0;//lambda的分子        //求的是当前独有邻居与共同邻居的相似度之和之和+节点2与共同邻居的相似度之和        for(s_4=s_4_count;s_4<s_4_count+CN_Num;s_4++)        {            int loc_1;            int loc_2;            loc_1=ThisEA.N_1_Loc[s_4*4+0];//(Node_N_1,NodeCN)所在行            loc_2=ThisEA.N_1_Loc[s_4*4+1];//(Node_N_1,NodeCN)所在列            lambda_numerator=lambda_numerator+(1-EdgeWithAttachmentTable[loc_1].Pointer[loc_2].dist);            loc_1=ThisEA.N_1_Loc[s_4*4+2];//(node2,NodeCN)所在行            loc_2=ThisEA.N_1_Loc[s_4*4+3];//(node2,NodeCN)所在列            lambda_numerator=lambda_numerator+(1-EdgeWithAttachmentTable[loc_1].Pointer[loc_2].dist);        }        double lambda_denominator=0;//lambda的分母        //求的是当前独有邻居的所有边的相似度之和        for(int s_5=0;s_5<EdgesOfNodeTable[Ngh_N_1].EdgeNum;s_5++)        {            int loc_r=EdgesOfNodeTable[Ngh_N_1].Pointer[s_5].Row;            int loc_c=EdgesOfNodeTable[Ngh_N_1].Pointer[s_5].Column;            lambda_denominator=lambda_denominator+(1-EdgeWithAttachmentTable[loc_r].Pointer[loc_c].dist);        }        double lambda=(double)lambda_numerator/(double)lambda_denominator;

说明图:
独有邻居说明图
lambda公式:
lambda公式

节点1独有邻居影响

        double parameter=(lambda>beta)?1:-1;        if(parameter==1)            N_1_I=N_1_I+parameter*lambda/(double)NodeTable[ThisNode_1-1].NodeNum*sin(1-Distance_N_N_1);        else            N_1_I=N_1_I+parameter*(beta-lambda)/(double)NodeTable[ThisNode_1-1].NodeNum*sin(1-Distance_N_N_1);        s_3++;//node1独有邻居下标    }

独有邻居影响EI公式:
独有邻居影响EI

三种交互模式总影响

    D[ThisEdgeId] = D[ThisEdgeId]+(-(N_1_I+N_2_I)-(((double)1.0/(double)NodeTable[ThisNode_1-1].NodeNum+(double)1.0/(double)NodeTable[ThisNode_2-1].NodeNum)*sin(1-ThisEA.dist) +CI));    if(D[ThisEdgeId]<0)        D[ThisEdgeId]=0;    if(D[ThisEdgeId]>1)        D[ThisEdgeId]=1;}

三种交互模式总影响公式:
总影响

终止迭代判断

double sum_1=0;//网络中每条边的距离之和double sum_2=0;//更新后每条边的距离之和int EdgeCounter=0;for(int s_1=0;s_1<NetNodeNum;s_1++)    for(int s_2=0;s_2<EdgeWithAttachmentTable[s_1].EdgeNum;s_2++)    {        sum_1=sum_1+EdgeWithAttachmentTable[s_1].Pointer[s_2].dist;        sum_2=sum_2+D[EdgeCounter];        EdgeCounter++;    }    if(sum_1==sum_2||Loop>1000)        Terminate=0;//结束迭代

更新距离

EdgeCounter=0;for(int s_1=0;s_1<NetNodeNum;s_1++)    for(int s_2=0;s_2<EdgeWithAttachmentTable[s_1].EdgeNum;s_2++)    {        EdgeWithAttachmentTable[s_1].Pointer[s_2].dist=D[EdgeCounter];        EdgeCounter++;    }

五、发现社区并输出结果

FindClusters(argv[2]);

建立新的节点表,距离等于1的边(邻居节点)不在考虑范围内

结合队列,通过广度优先搜索算法发现簇

int clusters[NetNodeNum+1];//每个节点所在簇,cluster[0]未被使用for(int k=0;k<=NetNodeNum;k++)    clusters[k]=-1;int Q[NetNodeNum];//队列int ClusterID=1;//簇的值,从1开始int Terminate=1;//终止条件while(Terminate){    Terminate = 0;      int id;    for(id=1; id<=NetNodeNum; id++)        if(clusters[id]==-1)         {//开始每个节点的簇均为-1,表示该节点尚未分簇            Terminate = 1;//有尚未分簇的节点便不能终止循环            clusters[id] = ClusterID;//开始,网络中第一个节点所在簇为1               Q[0] = id;//插入队列,last从-1到0            int first=-1;            int last = 0;  //队尾                 int v;            while(first!=last)            {  //队列不为空                v = Q[++first];  //出队列保存到v                for(int len=0; len<NodeTable_New[v-1].NodeNum; len++) {                    int RelatedNode = NodeTable_New[v-1].Pointer[len];                        if(clusters[RelatedNode]==-1)                         {                            Q[++last] = RelatedNode; //入队列                            clusters[RelatedNode] = ClusterID;                        }                }            }            ClusterID = ClusterID + 1;        }}// 【将簇保存在二维数组】FILE * fout = fopen(outputfile,"w");if(fout==NULL)    printf("opening outputfile fails\n"); exit(0);for(int i=1; i<=NetNodeNum; i++)    fprintf(fout, "%d %d\n", i, clusters[i]);//网络节点所在簇fclose(fout);

说明图
社区发现

原创粉丝点击