您的位置:首页 > 理论基础 > 计算机网络

004C语言 实现小世界网络

2015-10-24 20:49 609 查看

1简介:

小世界网络最早由Watts和Strogtz在1998年提出,小世界网络存在于数学、物理学和社会学中,是一种数学图的模型。在这种图中大部份的结点不与彼此邻接,但大部份结点可以通过任一其它节点经少数几步就可以产生联系。若将一个小世界网络中的点代表一个人,而联机代表人与人之间是相互认识的,则这小世界网络可以反映陌生人通过彼此共同认识的人而起来产生联系关系的小世界现象。(还记得那个著名的六度分隔理论吗?)

在小世界网络之前,人们研究的较多的是较稀疏的邻近耦合网络和随机网络,但是这两种网络都有其局限性(有兴趣可以自己查阅资料),不能准确地刻画现实世界的特性。所以小世界网络应运而生,其核心思想是随机化重连,通过随机概率的变化实现了邻近耦合网络到随机网络的过渡,而这个过渡就是小世界网络。

下面介绍这个随机化重连的规则:

1、从规则图开始:考虑一个含有N个点的最近邻耦合网络,它们围成一个环,其中每个节点都与它左右相邻的各K/2节点相连,K是偶数。

2、随机化重连:以概率p随机地从新连接网络中的每个边,取一个点顺时针重连间隔为0点之间的边,一端固定,另一端重连,顺时针一圈之后再重连间隔为1点之间的边(具体这个规则可以看Collective dynamics of ‘small-world’ networks这篇论文)。其中规定,任意两个不同的节点之间至多只能有一条边,并且每一个节点都不能有边与自身相连。

图示:



以上就是构建小世界网络的WS算法,但是这种规则有一个问题,就是会导致一些节点被孤立(因为可能连接节点的边都被重连了而却没有边连接这个节点),有兴趣的可以了解一下另一种NW算法,其核心思想是随机化加边,当然了,写论文的两位也意识到了这个问题,于是他们提出了一个规则来尽可能避免,那就是N>>K>>ln(N)>>1,(关于这个大家可以好好思考一下)。

如果想对小世界有一个比较准确完整的了解,百度是没用的,应该直接看1998年那篇论文:Collective dynamics of ‘small-world’ networks。需要的可以留言。

2最短路径:

在构建小世界网络时不可避免的要计算点对之间的最短路径,这里介绍Floyd算法,这个算法虽然时间复杂度有些大O(n^3),但是其简洁深刻真是我印象深刻,其真正核心的代码用C语言描述也只有5行!关于Floyd算法可以百度更多信息,这里不做更多介绍。

3构建思路:

实现确定思路是很重要的,这里我选择在栈外开辟一个较大的数组来描述连接情况,简单的思路表述如下图:



4编程实现:

1、一些预先处理

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <time.h>
#include <math.h>
#define Node_number 1000

typedef struct List
{
int link;
struct List *next;
}C_List;

int k_value = 100;
int Link[Node_number][Node_number];
double C_value[Node_number];
int min_Length[Node_number][Node_number];

void Initial(void);
void OutputData(void);
void ReLink(double p);
void Caculate_min_Length(void);
void Caculate_C(void);
2、主函数

int main(void)
{
system("color 0A");
printf("number of nodes is %d(ln(N)=%f)\nvalue of k is %d\n", Node_number, log(Node_number), k_value);
printf("input value of p:");
double p_value = 0;
scanf("%lf", &p_value);
Initial();
ReLink(p_value);
Caculate_min_Length();
Caculate_C();
OutputData();
return 0;
}
3、构建最近耦合网络

void Initial(void)
{
for (int j = 0; j < Node_number; j++)
{
for (int i = 0; i < Node_number; i++)
Link[i][j] = Node_number;

for (int temp = -k_value/2; temp <= k_value/2; temp++)
Link[(j + temp + Node_number)%Node_number][j] = 1;

Link[j][j] = 0;
}
for (int i = 0; i < Node_number; i++)
for (int j = 0; j < Node_number; j++)
min_Length[i][j] = Link[i][j];

}
4、随机重连

void ReLink(double p)
{
srand((unsigned)time(NULL));
for (int temp = 1; temp <= k_value/2; temp++)
{
for (int i = temp, j = 0; j < Node_number; i++,j++)
{
if((double)rand()/RAND_MAX < p)
{
int true = 1;
while(true)
{
int temp_row = rand()%Node_number;
if(Link[temp_row][j] == Node_number)
{
Link[temp_row][j] = Link[j][temp_row] = 1;
true = 0;
}
}
Link[(i+Node_number)%Node_number][j] = Node_number;
Link[j][(i+Node_number)%Node_number] = Node_number;
}
}
}
for (int i = 0; i < Node_number; i++)
for (int j = 0; j < Node_number; j++)
min_Length[i][j] = Link[i][j];//之前一直忘了
}
5、计算最短路径

void Caculate_min_Length(void)
{
for (int Order = 0; Order < Node_number; Order++)
{
for (int i = 0; i < Node_number; i++)
{
for (int j = 0; j < Node_number; j++)
{
if (min_Length[i][Order] + min_Length[Order][j] < min_Length[i][j])
min_Length[i][j] = min_Length[i][Order] + min_Length[Order][j];
}
}
}
}
6、计算聚类系数

void Caculate_C(void)
{
C_List *pHead = (C_List *)malloc(sizeof(C_List));
pHead->link = -1;
for (int j = 0; j < Node_number; j++)
{
C_List *pNext = pHead;
C_List *pTail = NULL;
C_List *pMove = NULL;
int count = 0;
for (int i = 0; i < Node_number;
4000
i++)
{
if (Link[i][j] == 1)
{
pTail = (C_List *)malloc(sizeof(C_List));
pTail->link = i;
pTail->next = NULL;
pNext->next = pTail;
pNext = pTail;
count++;
}
}
int actual_link = 0;
pNext = pHead->next;
while (pNext != NULL)
{
pMove = pHead->next;
while (pMove != NULL)
{
if(Link[pNext->link][pMove->link] == 1)
actual_link++;
pMove = pMove->next;
}
pNext = pNext->next;
}
C_value[j] = (double)actual_link/(count*(count-1));
}
//内存就让他去吧
}
7、输出数据

void OutputData(void)
{
int sum = 0;
double	total = 0;
FILE *fp_link = fopen ("exam_Link.txt", "w");
FILE *fp_length = fopen ("exam_min_Length.txt", "w");
FILE *fp_C = fopen("C_value.txt", "w");
for (int i = 0; i < Node_number; i++)
{
for (int j = 0; j < Node_number; j++)
{
sum += min_Length[i][j];
fprintf(fp_link, "%d\t", Link[i][j]);
fprintf(fp_length, "%d\t", min_Length[i][j]);
}
total += C_value[i];
fprintf(fp_link, "\n");
fprintf(fp_length, "\n");
fprintf(fp_C, "%f\n", C_value[i]);
}
printf("C:%f\tmin_L:%f", total/Node_number, (double)sum/((Node_number-1)*Node_number));
fclose(fp_link);
fclose(fp_length);
fclose(fp_C);
}


5结果分析

1、聚类系数和最短平均路径随随机化概率p的变化的趋势




可以看到随机化概率的增大,最短路径急剧减小而聚类系数缓慢减小,这时候网络在具有较高聚类系数的同时具有较小的平均最短路径,也就是一个小世界网络了。再来看看1998年论文中的原图吧。(默默承认自己的数据取的太少,作图水准太低)



由于数据和编程手段的不同,还是有一些差异的,但是其趋势是明显相同的。

接下来看一下p(随机化重连的概率)取不同值时的连接点对分布







以及p取不同值时的最短平均路径在点对之间的分布(貌似p=0时的图仔细看有好玩的视觉错误)













6收获总结

@一定充分构思好再开始敲代码,直接写程序的行为永远是愚蠢的;

@细节问题一定要注意,比如某个矩阵是否更新,细节直接决定成败,没错,是直接。

@一定要找个完整的时间完成,很多事情零零散散完成都是严重影响效率和心情的,最好找个阳光明媚的上午敲完。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息