|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
用python语言描述六度空间理论
你和任何一个陌生人之间所间隔的人不会超过6个,也就是说,最多通过6个中间人你就能够认识任何一个陌生人。(20世纪60年代每个心理学家斯坦利*米尔格拉姆提出)
六度空间理论的出现使得人们对于人际关系网络的威力有了新的认识。但为什么偏偏是"六度",而不是"七度""八度"或者"千百度"呢?
这可能要从人际关系网络的另外一个特征﹣-"150定律"来寻找解释。"150定律"指出,人类智力允许一个人维持稳定社交关系的人数上限是148人,四舍五入大约是150人。这样我们可以对六度空间理论做如下数学解释(并非数学证明):若每个人平均认识150人,其六度便是150=11390625000000,消除一些重复的结点,也远远超过了整个地球人口的若干倍。
如果需要使用BFS等遍历或者队列:
from abc import ABCMeta, abstractmethod, abstractproperty
import sys
class Node(object):
def __init__(self, data=None, next=None):
self.data = data
self.next = next
class LinkQueue:
def __init__(self):
self.front = None # 队首指针
self.rear = None # 队尾指针
def clear(self):
'''将队列置空'''
self.front = None
self.rear = None
def isEmpty(self):
'''判断队列是否为空'''
return self.front is None
def length(self):
'''返回队列的数据元素个数'''
p = self.front
i = 0
while p is not None:
p = p.next
i += 1
return i
def peek(self):
'''返回队首元素'''
if self.isEmpty():
return None
else:
return self.front.data
def offer(self, x):
'''将数据元素x插入到队列成为队尾元素'''
s = Node(x, None)
if not self.isEmpty():
self.rear.next = s
else:
self.front = s
self.rear = s
def poll(self):
'''将队首元素删除并返回其值'''
if self.isEmpty():
return None
p = self.front
self.front = self.front.next
if p == self.rear: # 删除结点为队尾结点时需要修改rear
self.rear = None
return p.data
def display(self):
'''输出队列中的所有元素'''
p = self.front
while p is not None:
print(p.data, end=' ')
p = p.next
class IGraph(metaclass=ABCMeta):
@abstractmethod
def createGraph(self):
'''创建图'''
pass
@abstractmethod
def getVNum(self):
'''返回图中的顶点数'''
pass
@abstractmethod
def getENum(self):
'''返回图中的边数'''
pass
@abstractmethod
def getVex(self, i):
'''返回位置为i的顶点值'''
pass
@abstractmethod
def locateVex(self, x):
'''返回值为x的顶点位置'''
pass
@abstractmethod
def firstAdj(self, i):
'''返回结点的第一个邻接点'''
pass
@abstractmethod
def nextAdj(self, i, j):
'''返回相对于j的下一个邻接点'''
pass
class MGraph(IGraph):
# 图类别静态常量
GRAPHKIND_UDG = 'UDG'
GRAPHKIND_DG = 'DG'
GRAPHKIND_UDN = 'UDN'
GRAPHKIND_DN = 'DN'
def __init__(self, kind=None, vNum=0, eNum=0, v=None, e=None):
self.kind = kind # 图的种类
self.vNum = vNum # 图的顶点数
self.eNum = eNum # 图的边数
self.v = v # 顶点列表
self.e = e # 邻接矩阵
def createUDG(self, vNum, eNum, v, e):
self.vNum = vNum
self.eNum = eNum
self.v = [None] * vNum # 构造顶点集
for i in range(vNum):
self.v[i] = v[i]
self.e = [[0] * vNum] * vNum # 构造边集
for i in range(eNum):
a, b = e[i]
m, n = self.locateVex(a), self.locateVex(b)
self.e[m][n] = self.e[n][m] = 1
def createDG(self, vNum, eNum, v, e):
self.vNum = vNum
self.eNum = eNum
self.v = [None] * vNum # 构造顶点集
for i in range(vNum):
self.v[i] = v[i]
self.e = [[0] * vNum] * vNum # 构造边集
for i in range(eNum):
a, b = e[i]
m, n = self.locateVex(a), self.locateVex(b)
self.e[m][n] = 1
def createUDN(self, vNum, eNum, v, e):
self.vNum = vNum
self.eNum = eNum
self.v = [None] * vNum # 构造顶点集
for i in range(vNum):
self.v[i] = v[i]
self.e = [[sys.maxsize] * vNum] * vNum # 初始化边集
for i in range(eNum):
a, b, w = e[i]
m, n = self.locateVex(a), self.locateVex(b)
self.e[m][n] = self.e[n][m] = w
def createDN(self, vNum, eNum, v, e):
self.vNum = vNum
self.eNum = eNum
self.v = [None] * vNum # 构造顶点集
for i in range(vNum):
self.v[i] = v[i]
self.e = [[sys.maxsize] * vNum] * vNum # 初始化边集
for i in range(eNum):
a, b, w = e[i]
m, n = self.locateVex(a), self.locateVex(b)
self.e[m][n] = w
def locateVex(self, x):
for i in range(self.vNum):
if self.v[i] == x:
return i
return -1
def firstAdj(self, i):
if i < 0 or i >= self.vNum:
raise Exception("第%s个顶点不存在" % i)
for j in range(self.vNum):
if self.e[i][j] != 0 and self.e[i][j] < sys.maxsize:
return j
return -1
def nextAdj(self, i, j):
if j == self.vNum - 1:
return -1
for k in range(j + 1, self.vNum):
if self.e[i][k] != 0 and self.e[i][k] < sys.maxsize:
return k
return -1
class VNode(object):
def __init__(self, data=None, firstNode=None):
self.data = data # 存放结点值
self.firstArc = firstNode # 第一条边
class ArcNode(object):
def __init__(self, adjVex, value, nextArc=None):
self.adjVex = adjVex # 边指向的顶点的位置
self.value = value # 边的权值
self.nextArc = nextArc # 指向下一条边
class ALGraph(IGraph):
# 图类别静态常量
GRAPHKIND_UDG = 'UDG'
GRAPHKIND_DG = 'DG'
GRAPHKIND_UDN = 'UDN'
GRAPHKIND_DN = 'DN'
def __init__(self, kind=None, vNum=0, eNum=0, v=None, e=None):
self.kind = kind # 图的种类
self.vNum = vNum # 图的顶点数
self.eNum = eNum # 图的边数
self.v = v # 顶点列表
self.e = e # 边信息
def createGraph(self):
if self.kind == self.GRAPHKIND_UDG:
self.createUDG()
elif self.kind == self.GRAPHKIND_DG:
self.createDG()
elif self.kind == self.GRAPHKIND_UDN:
self.createUDN()
elif self.kind == self.GRAPHKIND_DN:
self.createDN()
def createUDG(self):
'''创建无向图'''
v = self.v
self.v = [None] * self.vNum
for i in range(self.vNum):
self.v[i] = VNode(v[i])
for i in range(self.eNum):
a, b = self.e[i]
u, v = self.locateVex(a), self.locateVex(b)
self.addArc(u, v, 1)
self.addArc(v, u, 1)
def createDG(self):
'''创建有向图'''
v = self.v
self.v = [None] * self.vNum
for i in range(self.vNum):
self.v[i] = VNode(v[i])
for i in range(self.eNum):
a, b = self.e[i]
u, v = self.locateVex(a), self.locateVex(b)
self.addArc(u, v, 1)
def createUDN(self):
'''创建无向网'''
v = self.v
self.v = [None] * self.vNum
for i in range(self.vNum):
self.v[i] = VNode(v[i])
for i in range(self.eNum):
a, b, w = self.e[i]
u, v = self.locateVex(a), self.locateVex(b)
self.addArc(u, v, w)
self.addArc(v, u, w)
def createDN(self):
'''创建有向网'''
v = self.v
self.v = [None] * self.vNum
for i in range(self.vNum):
self.v[i] = VNode(v[i])
for i in range(self.eNum):
a, b, w = self.e[i]
u, v = self.locateVex(a), self.locateVex(b)
self.addArc(u, v, w)
def addArc(self, i, j, value):
'''插入边结点'''
arc = ArcNode(j, value)
arc.nextArc = self.v[i].firstArc
self.v[i].firstArc = arc
def firstAdj(self, i):
'''查找第一个邻接点'''
if i < 0 or i >= self.vNum:
raise Exception("第%s个结点不存在" % i)
p = self.v[i].firstArc
if p is not None:
return p.adjVex
return -1
def nextAdj(self, i, j):
'''返回i相对于j的下一个邻接点'''
if i < 0 or i >= self.vNum:
raise Exception("第%s个结点不存在" % i)
p = self.v[i].firstArc
while p is not None:
if p.adjVex == j:
break
p = p.nextArc
if p.nextArc is not None:
return p.nextArc.adjVex
return -1
def getVNum(self):
'''返回顶点数'''
return self.vNum
def getENum(self):
'''返回边数'''
return self.eNum
def getVex(self, i):
'''返回第i个顶点的值'''
if i < 0 or i >= self.vNum:
raise Exception("第%s个顶点不存在" % i)
return self.v[i].data
def locateVex(self, x):
'''返回值为x的顶点的位置'''
for i in range(self.vNum):
if self.v[i].data == x:
return i
return -1
def getArcs(self, u, v):
'''返回顶点u到顶点v的距离'''
if u < 0 or u >= self.vNum:
raise Exception("第%s个结点不存在" % u)
if v < 0 or v >= self.vNum:
raise Exception("第%s个结点不存在" % v)
p = self.v[u].firstArc
while p is not None:
if p.adjVex == v:
return p.value
p = p.nextArc
return sys.maxsize
#######################################
def BFSTraverse(g):
global visited
# 建立访问标志数组
visited = [False] * g.getVNum()
count = 0
# 以每个顶点作为起始顶点进行遍历
for i in range(g.getVNum()):
if not visited[i]:
count += 1
print(f'第{count}个连通块:', end=' ')
BFS(g, i)
print()
def BFS(g, i):
# 建立辅助队列
q = LinkQueue()
# 将起点加入队列
q.offer(i)
while not q.isEmpty():
u = q.poll()
# 标记顶点已访问
visited[u] = True
print(g.getVex(u), end=' ')
v = g.firstAdj(u)
while v != -1:
# 顶点未访问的邻接点入队
if not visited[v]:
q.offer(v)
# 获取下一个邻接点
v = g.nextAdj(u, v)
########################################
v = [1, 2, 3, 4, 5, 6]
e = [(1, 2), (2, 3), (4, 5)]
g = ALGraph(ALGraph.GRAPHKIND_UDG, len(v), len(e), v, e) # 引用类的属性
g.createGraph()
BFSTraverse(g)
##############################################################
def DFSTraverse(g):
global visited
# 建立访问标志数组
visited = [False] * g.getVNum()
# 以每个顶点作为起始顶点进行遍历
for i in range(g.getVNum()):
if not visited[i]:
DFS(g, i)
def DFS(g, i):
visited[i] = True
print(g.getVex(i), end=' ')
v = g.firstAdj(i)
while v > 0:
if not visited[v]:
DFS(g, v)
v = g.nextAdj(i, v)
class CloseEdge(object):
def __init__(self, adjVex, lowCost):
self.adjVex = adjVex # 在结合U中的顶点的值
self.lowCost = lowCost # 到集合U的最小距离
class MiniSpanTree(object):
def PRIM(g, u):
'''从值为u的顶点出发构造最小生成树,返回由生成树边组成的二维数组'''
tree = [[None, None] for i in range(g.getVNum() - 1)]
count = 0
closeEdge = [None] * g.getVNum()
k = g.locateVex(u)
for j in range(g.getVNum()):
if k != j:
closeEdge[j] = CloseEdge(u, g.getArcs(k, j))
closeEdge[k] = CloseEdge(u, 0)
for i in range(1, g.getVNum()):
k = MiniSpanTree.getMinMum(closeEdge)
tree[count][0] = closeEdge[k].adjVex
tree[count][1] = g.getVex(k)
count += 1
closeEdge[k].lowCost = 0
for j in range(g.getVNum()):
if g.getArcs(k, j) < closeEdge[j].lowCost:
closeEdge[j] = CloseEdge(g.getVex(k), g.getArcs(k, j))
return tree
def getMinMum(closeEdge):
minvalue = sys.maxsize
v = -1
for i in range(len(closeEdge)):
if closeEdge[i].lowCost != 0 and closeEdge[i].lowCost < minvalue:
minvalue = closeEdge[i].lowCost
v = i
return v
class ShortestPath:
def Djikstra(g, v0):
# 存放最短路径,p[v][k]表示从v0到v的最短路径中经过的第k个点
p = [([-1] * g.getVNum()) for i in range(g.getVNum())]
# 存放最短路径长度
D = [sys.maxsize] * g.getVNum()
# 若已找到最短路径,finish[v]为True
finish = [False] * g.getVNum()
v0 = g.locateVex(v0)
for v in range(g.getVNum()):
D[v] = g.getArcs(v0, v)
if D[v] < sys.maxsize:
# 从起点直接可以到达
p[v][0] = v0
p[v][1] = v
p[v0][0] = v0 # 起点本身可以直接到达
D[v0] = 0
finish[v0] = True
v = -1
for i in range(1, g.getVNum()):
minvalue = sys.maxsize
for w in range(g.getVNum()):
# 找出所有最短路径中的最小值
if not finish[w]:
if D[w] < minvalue:
v = w
minvalue = D[w]
finish[v] = True
# 更新当前的最短路径
for w in range(g.getVNum()):
if not finish[w] and g.getArcs(v, w) < sys.maxsize and (minvalue + g.getArcs(v, w) < D[w]):
D[w] = minvalue + g.getArcs(v, w)
for k in range(g.getVNum()):
p[w][k] = p[v][k]
if p[w][k] == -1:
p[w][k] = w
break
dis = {g.getVex(i): D[i] for i in range(g.getVNum())}
# 返回到各点最短路的字典与路径矩阵
return dis, p
def printDjikstraPath(g, v0, p):
# v0到各点的输出最短路径,即p[v][0]到p[v][j]直到p[v][j]==-1
u = v0
v0 = g.locateVex(v0)
for i in range(g.getVNum()):
v = g.getVex(i)
print('%s->%s的最短路径为:' % (u, v), end=' ')
if p[i][0] != -1:
print(g.getVex(p[v0][0]), end='')
for k in range(1, g.getVNum()):
if p[i][k] == -1:
break
print('->%s' % g.getVex(p[i][k]), end='')
print(',长度为:%s' % dis[v])
def Floyd(g): # 多源点最短路径
vNum = g.getVNum()
D = [[sys.maxsize] * vNum for i in range(vNum)]
p = [[-1] * vNum for i in range(vNum)]
for u in range(vNum):
for v in range(vNum):
D[u][v] = g.getArcs(u, v) if u != v else 0
if D[u][v] < sys.maxsize:
p[u][v] = u
for k in range(vNum):
for i in range(vNum):
for j in range(vNum):
if D[i][j] > D[i][k] + D[k][j]:
D[i][j] = D[i][k] + D[k][j]
p[i][k] = i
p[i][j] = p[k][j]
dis = {(g.getVex(u), g.getVex(v)): D[u][v] for u in range(vNum) for v in range(vNum)}
return dis, p
def printFloydPath(g, p):
vNum = g.getVNum()
for u in range(vNum):
for v in range(vNum):
if u == v:
print('%s->%s的最短路径为: %s' % (g.getVex(u), g.getVex(v), g.getVex(u)))
continue
flag = True
path = [v]
t = p[u][path[0]]
while t != u:
if t == -1:
flag = False
break
path = [t] + path
t = p[u][t]
print('%s->%s的最短路径为:' % (g.getVex(u), g.getVex(v)), end=' ')
if flag:
print(g.getVex(u), end='')
for node in path:
print('->%s' % g.getVex(node), end='')
print()
v = [1, 2, 3, 4, 5, 6]
e = [(1, 2, 45), (1, 3, 15), (1, 5, 15),
(3, 1, 10), (2, 4, 20), (2, 5, 15),
(2, 6, 15), (3, 2, 10), (3, 4, 60),
(4, 2, 30), (4, 6, 20)]
g = ALGraph(ALGraph.GRAPHKIND_UDN, len(v), len(e), v, e)
g.createGraph()
dis, p = ShortestPath.Djikstra(g, 1)
ShortestPath.printDjikstraPath(g, 1, p)
def findInDegree(g):
indegree = [0] * g.getVNum()
# 计算每个点的入度
for u in range(g.getVNum()):
v = g.firstAdj(u)
while v != -1:
indegree[v] += 1
v = g.nextAdj(u, v)
return indegree
def topoSort(g):
count = 0
indegree = findInDegree(g)
s = LinkStack()
topo = []
for i in range(g.getVNum()):
# 入度为0的点入栈
if indegree[i] == 0:
s.push(i)
while not s.isEmpty():
u = s.pop()
topo.append(u)
count += 1
# 对该点的每个邻接点的入度-1
v = g.firstAdj(u)
while v != -1:
indegree[v] -= 1
if indegree[v] == 0:
s.push(v)
v = g.nextAdj(u, v)
if count < g.getVNum():
return None
return [g.getVex(u) for u in topo]
def topoOrder(g):
count = 0
indegree = findInDegree(g)
s = LinkStack()
t = LinkStack() # 记录拓扑顺序
ve = [0] * g.getVNum()
for i in range(g.getVNum()):
# 入度为0的点入栈
if indegree[i] == 0:
s.push(i)
while not s.isEmpty():
u = s.pop()
t.push(u)
count += 1
# 对该点的每个邻接点的入度-1
v = g.firstAdj(u)
while v != -1:
indegree[v] -= 1
if indegree[v] == 0:
s.push(v)
# 更新最早发生时间
if ve[u] + g.getArcs(u, v) > ve[v]:
ve[v] = ve[u] + g.getArcs(u, v)
v = g.nextAdj(u, v)
if count < g.getVNum():
return None, None
return ve, t
def criticalPath(g):
ve, t = topoOrder(g)
if ve is None:
return None
vl = [ve[t.top.data]] * g.getVNum()
# 逆拓扑序求各顶点的vl值
while not t.isEmpty():
u = t.pop()
v = g.firstAdj(u)
while v != -1:
if vl[v] - g.getArcs(u, v) < vl[u]:
vl[u] = vl[v] - g.getArcs(u, v)
v = g.nextAdj(u, v)
# 输出关键活动
print("关键活动为:", end='')
for i in range(g.getVNum()):
if ve[i] == vl[i]:
print(g.getVex(i), end=' ')
print()
# 6.6
v = ['A', 'B', 'C', 'D', 'E', 'F']
e = [
('A', 'B', 7), ('A', 'C', 5), ('A', 'D', 1),
('B', 'D', 6), ('B', 'E', 3), ('C', 'D', 7),
('C', 'F', 2), ('D', 'E', 6), ('D', 'F', 4),
('E', 'F', 7)
]
g1 = ALGraph(ALGraph.GRAPHKIND_UDN, len(v), len(e), v, e)
g1.createGraph()
print(MiniSpanTree.PRIM(g1, 'A'))
使用以上的代码 |
|