【复杂网络学习笔记】2:无标度网络的建立

来源:互联网 发布:如何使用数据透视表 编辑:程序博客网 时间:2024/05/17 01:04

scale - free network, 现实世界的网络大部分都不是随机网络,少数的节点往往拥有大量的连接,而大部分节点却很少,一般而言他们符合二八定律。将度分布符合幂律分布的复杂网络称为无标度网络。

如互联网,大型软件的结构特性都属于无标度网络:


只要攻击那些度数很多的关键节点就能引起最大的攻击效益。

这也正体现了无标度网络对蓄意攻击的脆弱性(李青老师用了一个有趣的阿喀琉斯踵的故事),总结如下:



*通用异常类Error.h

#ifndef ERROR_H#define ERROR_H#include<iostream>using namespace std;//通用异常类class Error{private:char message[100];//异常信息public:Error(const char *mes = "一般性异常!"); //构造函数 ~Error(void) {}; //析构函数void Show() const; //显示异常信息};Error::Error(const char *mes){strcpy_s(message, 100, mes); //复制异常信息}void Error::Show()const{cout << message << endl; //显示异常信息}#endif

*无向图邻接网的边节点类Arc.h

#ifndef NULL#define NULL (void *)0#endif#ifndef ARC_H#define ARC_H//边节点类struct Arc{int iNum; //弧的另一端的节点的序号Arc* pNext; //指向下一边节点的指针Arc(int n, Arc* next); //构造序号为n,下一节点指向next的边节点};Arc::Arc(int n, Arc* next){iNum = n;pNext = next;}#endif


*无向图邻接表的顶点节点类Vex.h

#ifndef NULL#define NULL 0#endif#ifndef VEX_H#define VEX_H#include "arc.h"struct Vex{int k;//度数Arc* pFirst; //指向边节点表Vex();//空构造};Vex::Vex(){k = 0;//度数一开始为0pFirst = NULL;}#endif


这里补充一下无标度网络的生成过程,直接搬老师PPT好了:



*邻接网络(无标度模型)类NetWork.h

#ifndef NULL#define NULL (void *)0#endif#ifndef NETWORK_H#define NETWORK_H#include "vex.h"#include "error.h"#define N 4//最近邻网络//邻接网络(无标度模型)类struct NetWork{int vexNum; //顶点的数目Vex* vexTable; //顶点表int maxNum;//最大数目int numMod;//k值总和,用于求余NetWork(int v,int n); //构造有v个顶点的空表void Clear(); //清空边节点void BuildArc(int a, int b); //构造从a到b的边void Step1(); //清空全表,然后形成部分最近邻网络void Step2();//每次引入一个新节点,以概率连接到之前的点上void Show(); //简易的显示该网络void DelArc(int a, int b); //删除从a到b的边bool HasArc(int a, int b); //查询是否有从a到b的边};NetWork::NetWork(int v,int n) //构造有v个顶点,最大为n的空表{if (n < v)throw Error("n不能比v小");vexTable = new Vex[maxNum = n];vexNum = v;numMod = 0;}void NetWork::Clear() //清空边节点{Arc* p;for (int i = 0; i < vexNum; i++){p = vexTable[i].pFirst; //从第一个边节点开始while (p != NULL){vexTable[i].pFirst = p->pNext; //first域连到p后去delete p; //删掉pp = vexTable[i].pFirst; //再次指向first的节点}vexTable[i].k = 0;}numMod = 0;//清空numMod}void NetWork::DelArc(int a, int b) //删除从a到b的边{if (a < 0 || b < 0 || a >= vexNum || b >= vexNum)throw Error("数组越界");if (a == b)throw Error("自身没有环");Arc *p, *q;//删除a->bif (vexTable[a].pFirst->iNum == b) //如果是第一个点{p = vexTable[a].pFirst;vexTable[a].pFirst = p->pNext;delete p;vexTable[a].k--;numMod -= 2;//维护}else //如果不是第一个点{q = vexTable[a].pFirst; //q在p前p = q->pNext;while (p != NULL){if (p->iNum == b) //找到了b的位置{q->pNext = p->pNext;delete p;vexTable[a].k--;numMod -= 2;//维护break;}}}//删除b->aif (vexTable[b].pFirst->iNum == a) //如果是第一个点{p = vexTable[b].pFirst;vexTable[b].pFirst = p->pNext;delete p;vexTable[b].k--;numMod -= 2;//维护}else //如果不是第一个点{q = vexTable[b].pFirst; //q在p前p = q->pNext;while (p != NULL){if (p->iNum == a) //找到了a的位置{q->pNext = p->pNext;delete p;vexTable[b].k--;numMod -= 2;//维护break;}}}}bool NetWork::HasArc(int a, int b) //查询是否有从a到b的边{if (a < 0 || b < 0 || a >= vexNum || b >= vexNum)throw Error("数组越界");if (a == b)throw Error("自身没有环");Arc* p;bool k = 0; //k=1时表示从a到b有边p = vexTable[a].pFirst; //不妨看a->b有没有,从第一个边节点开始while (p != NULL) //检索是否已经有边{if (p->iNum == b) //检索到,做标记并跳出{k = 1;break;}p = p->pNext; //没检索到,继续找}return k;}void NetWork::BuildArc(int a, int b) //建立从a到b的边{if (a < 0 || b < 0 || a >= maxNum || b >= maxNum)throw Error("数组越界");if (a == b)throw Error("不能自身成环");Arc* p;bool k = 0; //k=1时表示从a到b有边p = vexTable[a].pFirst; //不妨看a->b有没有,从第一个边节点开始while (p != NULL) //检索是否已经有边{if (p->iNum == b) //检索到,做标记并跳出{k = 1;break;}p = p->pNext; //没检索到,继续找}if (k == 0) //如果没有边,建立之{vexTable[a].pFirst = new Arc(b, vexTable[a].pFirst); //a能找到b同时vexTable[b].pFirst = new Arc(a, vexTable[b].pFirst); //b也要能找到avexTable[a].k++;vexTable[b].k++;numMod += 2;//维护}}void NetWork::Step1() //清空全表,然后形成部分近邻网络{int n;if (N > vexNum)n = 2;elsen = N;Clear(); //清空for (int i = 0; i < vexNum; i++) //对每个节点i{for (int j = 1; j <= n / 2; j++) //建立其n最近邻关系{BuildArc(i, (i + j) % vexNum); //向后第j个BuildArc(i, (i - j + vexNum) % vexNum); //向前第j个}vexTable[i].k = n;//度数肯定为n,这句可有可无,Build时已经做好了}numMod = n*vexNum;//初始化,这句可有可无,Build时已经做好了}void NetWork::Step2(){int randomNum;//存储随机数int sum = 0;//sum用于寻找这个随机数落在哪里,这样就形成了概率for (int i = vexNum; i < maxNum; i++)//对后面未建立的每个节点{sum = 0;//每次sum都清空randomNum = rand() % numMod;//只要对numMod取余就一定在0~numMod之间for (int j = 0; j < i; j++){sum += vexTable[j].k;//sum不断加上这个k值if (sum>randomNum)//说明落在这里{BuildArc(i, j);//函数里面已经对k值和numMod进行维护了break;//找到后跳出小for()}}}vexNum = maxNum;//执行完后vexNum可以充满整个数组}void NetWork::Show() //显示{Arc* p; //辅助指针cout << "一共可以存" << maxNum << "个节点" << endl;for (int i = 0; i < vexNum; i++){cout << i << "("<<vexTable[i].k<<"):";p = vexTable[i].pFirst; //从第一条边开始while (p != NULL) //对于每条边{cout << "->" << p->iNum;p = p->pNext;}cout << endl;}}#endif

*程序入口wbd.cpp

// wbd.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>#include "NetWork.h" //邻接网络(无标度模型)类using namespace std;#define OK 25#define MAXI 100int _tmain(int argc, _TCHAR* argv[]){try{cout << "建立空网络(" << OK << "," << MAXI << ")后:" << endl;NetWork *pNet = new NetWork(OK,MAXI); //建立空网络(有效OK,满MAXI)pNet->Show(); //显示看一下cout<<endl << "形成N最近邻网络后:" << endl;pNet->Step1(); //对有效点形成N最近邻网络pNet->Show(); //显示看一下cout <<endl<< "偏好增长后:" << endl;pNet->Step2(); //偏好增长pNet->Show(); //显示看一下system("pause");return 0;}catch (Error er){er.Show();}return 0;}

运行结果:

先生成空网络,我这里有效=25,开的数组=100


再生成最近邻网络(是其它的什么网络也可以),我这里N=4


最后进行偏好增长,这是获取无标度特性的最关键的步骤





可以看到前面的节点因为度的基数大,被选中的概率也会大,后加进来的只有零星的几个再次被选中(编号24以后的那些不止有一条边的节点),说明这个建模是成功的。

小世界网络写完整后运行不出结果,有空继续debug吧。

0 0
原创粉丝点击