【复杂网络学习笔记】1:基本知识和小世界网络初步建立

版权声明:本文为博主原创学习笔记,如需转载请注明来源。 https://blog.csdn.net/SHU15121856/article/details/70199009

这学期和李青老师学习复杂网络的一些基础知识,并进行建模。

复杂网络在生活中很常见,这学期主要学习其中的两种模型——小世界模型和无标度模型。

著名的小世界实验发现了社会群体中人和人之间六度分离的关系(任意两个人之间的平均路径经过了约6个中间人)。如何解释一个人所认识的人并不多,但是却总是有六度分离的现象,就有人提出了小世界的模型。

 

即人和人之间的社会是由这样的朋友圈组成的。

 

一般使用这两个特征来衡量网络:

①平均路径长:网络中所有节点对的路径长度的平均值。

②聚类系数:假设某个节点有k条边,则这k条边连接的节点(k个)之间最多可能存在的边的条数为k(k-1)/2,用实际存在的边数除以最多可能存在的边数得到的分数值,定义为这个节点的聚类系数。聚类系数是网络的局部特征,反映了相邻两个人之间朋友圈子的重合度,即该节点的朋友之间也是朋友的程度。

 

小世界网络的特征就是平均路径长较短,而聚类系数较大。

 

建立小世界模型,可以通过下面两个步骤:

①形成N最近邻网络:考虑一个含有N个点的最近邻耦合网络,它们围成一个环,其中每个结点都与其左右相邻的各k/2个结点相连(k为偶数)。

②随机化重连:以概率p随机地重新连接网络中的每个边。即:将边的一个端点保持不变,而另一个端点取为网络中随机选择的一个结点。规定,任意两个不同的结点之间至多有一条边,且每个结点都不能有边与自身相连。

 

下面是今天写的建立小世界模型的代码,随机化重连的实现还没有想好该怎么写,所以先注释了,明天去问李青老师。

这次用的编译器不是MinGW了而是VS了,代码有了些很有意思的地方。比如VS找不到NULL的宏定义,就自己写了它的宏定义之类的。

*通用异常类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 (void *)0
#endif

#ifndef VEX_H
#define VEX_H
#include "arc.h"
struct Vex
{
	Arc* pFirst; //指向边节点表
	Vex();//空构造
};
Vex::Vex()
{
	pFirst = NULL;
}
#endif

 

*邻接网络(小世界模型)类NetWork.h

 

#ifndef NULL
#define NULL (void *)0
#endif

#ifndef NETWORK_H
#define NETWORK_H
#include "vex.h"
#include "error.h"

//邻接网络(小世界模型)类
struct NetWork
{
	int vexNum; //顶点的数目
	Vex* vexTable; //顶点表

	NetWork(int v); //构造有v个顶点的空表
	void Clear(); //清空边节点
	void BuildVex(int a, int b); //构造从a到b的边
	void Step1(int n); //清空全表,然后形成n最近邻网络
	void Step2(int r); //以概率r%进行随机化重连
	void Show(); //简易的显示该网络
};

NetWork::NetWork(int v) //构造有v个顶点的空表
{
	vexTable = new Vex[vexNum=v];
}

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; //删掉p
			p = vexTable[i].pFirst; //再次指向first的节点
		}
	}
}

void NetWork::BuildVex(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; //没检索到,继续找
	}
	if (k == 0) //如果没有边,建立之
	{
		vexTable[a].pFirst = new Arc(b, vexTable[a].pFirst); //a能找到b同时
		vexTable[b].pFirst = new Arc(a, vexTable[b].pFirst); //b也要能找到a
	}
}

void NetWork::Step1(int n) //清空全表,然后形成n最近邻网络
{
	if (n > vexNum - 1)
		throw Error("n超限");
	if (n % 2 != 0)
		throw Error("n最近邻网络中n应为偶数");
	Clear(); //清空
	for (int i = 0; i < vexNum; i++) //对每个节点i
	{
		for (int j = 1; j <= n / 2; j++) //建立其n最近邻关系
		{
			BuildVex(i, (i + j) % vexNum); //向后第j个
			BuildVex(i, (i - j + vexNum) % vexNum); //向前第j个
		}
	}
}

void NetWork::Step2(int r) //以概率r%进行随机化重连
{
	if (r<0 || r>100)
		throw Error("随机化重连的概率不合法");
	int a, b; //辅助游标
	Arc* p; //辅助指针
	for (a = 0; a < vexNum; a++) //对于每个节点
	{
		p = vexTable[a].pFirst; //从第一条边开始
		while (p != NULL) //对于每条边
		{
			if (rand() % 100 < r) //生成0~99的伪随机数,它小于r的概率应为r%
			{
				//这里是随机化重连过程
				//删除a->旧点和旧点->a的关系
				//随机地找一个之前和a无连接的新点
				//增加a->新点和新点->a的关系
			}
		}
	}
}

void NetWork::Show() //显示
{
	Arc* p; //辅助指针
	for (int i = 0; i < vexNum; i++)
	{
		cout << i << ":";
		p = vexTable[i].pFirst; //从第一条边开始
		while (p != NULL) //对于每条边
		{
			cout <<"->"<< p->iNum;
			p = p->pNext;
		}
		cout << endl;
	}
}
#endif

 

*程序入口xsj.cpp

 

//#pragma warning(disable:4996) //忽略strcpy()函数不安全的warnning
#include "stdafx.h"
#include <iostream>
#include "NetWork.h" //邻接网络(小世界模型)类
using namespace std;

#define VEXNUM 100 //测试的节点个数
#define N 4 //最近邻网络个数
#define R 60 //随机化重连的概率*100

int _tmain(int argc, _TCHAR* argv[])
{
	try{
		NetWork *pNet = new NetWork(VEXNUM); //建立VEXNUM个节点的空邻接网络
		pNet->Step1(N); //形成N最近邻网络
		//pNet->Step2(R); //以概率R%随机化重连
		pNet->Show(); //显示看一下
		system("pause");
		return 0;
	}
	catch (Error er)
	{
		er.Show();
	}
}

 

将VEXNUM设置为100(全部完成后应该设置为1000以上),运行看一下当前结果是否正确。

 

部分运行结果:

 

看一下边缘是否正确

 

 

可以看到是一个合格的4最近邻网络。

 

祝好。

 

 

 

没有更多推荐了,返回首页