0. 原书勘误
《Python数据结构与算法分析(第2版)》(人民邮电出版社,ISBN:9787115517210),该书中的 Graph 对象的 addVertex() 方法有BUG,会引起潜在错误。原书代码:
def addVertex(self, key):
self.numVertices = self.numVertices + 1
newVertex = Vertex(key)
self.vertList[key] = newVertex
return newVertex
0.1 引起的BUG
我在使用其代码时,发现总是出现莫名其妙的数据丢失,后发现,其 addVertex() 方法有问题。Graph 对象的 addVertex() 方法 未判断 是否已经包含该顶点,而是直接覆盖该顶点对象,逻辑不够严密。
比如,有Graph包含顶点:
1 connectedTo: [7]
7 connectedTo: [1, 9]
然后我再次 addVertext(7),该图会变成:
1 connectedTo: [7]
7 connectedTo: []
顶点7的邻接表数据直接就被空值覆盖了,简单说就是顶点7的边和邻接点的数据全没了!
0.2 修复代码
其代码应改为:
def addVertex(self, key):
# https://blog.csdn.net/qilei2010博主注:
# 该书中此方法不够严谨,未判断该key是否已存在
# 这里我加上了if else
if key not in self.vertList:
self.numVertices = self.numVertices + 1
newVertex = Vertex(key)
self.vertList[key] = newVertex
return newVertex
else:
return self.vertList[key]
当然,这并非最合适的处理方式,但是直接悄无声息的覆盖原对象导致数据丢失是绝对不能容忍的错误。
以上为最新更新内容。
以下为原文。
1. 需求
因需要,需将List中数字依次按序转为双向图,如有列表
mylist = [1, 7, 9, 10, 6, 4]
需要转为邻接表存储的图,如下所示:
1 connectedTo: [7]
7 connectedTo: [1, 9]
9 connectedTo: [7, 10]
10 connectedTo: [9, 6]
6 connectedTo: [10, 4]
4 connectedTo: [6]
2. 图书案例代码
特研究了下Python的数据结构。参考了图书《Python数据结构与算法分析(第2版)》(人民邮电出版社,ISBN:9787115517210)中的顶点和图结构的实现代码。
(注:第0章节提到的代码中的Bug我已经修复)
该书中,图的顶点对象代码为:
class Vertex:
"""计算机数据结构-图的顶点-邻接表方式存储"""
def __init__(self, key):
self.id = key
self.connectedTo = {}
def addNeighbor(self, nbr, weight=0):
self.connectedTo[nbr] = weight
def __str__(self):
return str(self.id) + ' connectedTo: ' \
+ str([x.id for x in self.connectedTo])
def getConnections(self):
return self.connectedTo.keys()
def getId(self):
return self.id
def getWeight(self, nbr):
return self.connectedTo[nbr]
图结构的代码:
class Graph:
"""计算机数据结构-图"""
def __init__(self):
self.vertList = {}
self.numVertices = 0
def addVertex(self, key):
# https://blog.csdn.net/qilei2010博主注:
# 该书中此方法不够严谨,未判断该key是否已存在
# 这里我加上了if else
if key not in self.vertList:
self.numVertices = self.numVertices + 1
newVertex = Vertex(key)
self.vertList[key] = newVertex
return newVertex
else:
return self.vertList[key]
def getVertex(self, n):
if n in self.vertList:
return self.vertList[n]
else:
return None
def __contains__(self, n):
return n in self.vertList
def addEdge(self, f, t, cost=0):
if f not in self.vertList:
nv = self.addVertex(f)
if t not in self.vertList:
nv = self.addVertex(t)
self.vertList[f].addNeighbor(self.vertList[t], cost)
def getVertices(self):
return self.vertList.keys()
def __iter__(self):
return iter(self.vertList.values())
以上是该书中的数据结构-图的实现代码。在此基础上,我写了个函数:
def listToGraph(mylist):
"""将列表转图"""
graph = Graph()
# 将List所有元素转为图的顶点
for i in mylist:
graph.addVertex(i)
# 为图添加边 Edge
for i, v in enumerate(mylist):
if i - 1 >= 0:
left = mylist[i - 1]
graph.addEdge(v, left)
if i + 1 <= len(mylist) - 1:
right = mylist[i + 1]
graph.addEdge(v, right)
return graph
mylist = [1, 7, 9, 10, 6, 4] # 双向图,无权重
graph = listToGraph(mylist)
# 打印图
for key in graph.getVertices():
print(graph.getVertex(key)) # 打印图的顶点及该顶点的邻接顶点
3. 完整可运行代码
完整单一代码如下:
# -*- coding:utf-8 -*-
# 版本:Python 3.6+
# 功能:将List转为双向图
# 说明:部分代码来自图书《Python数据结构与算法分析(第2版)》
# (人民邮电出版社,ISBN:9787115517210)
# 作者:https://blog.csdn.net/qilei2010
class Vertex:
"""计算机数据结构-图的顶点-邻接表方式存储"""
def __init__(self, key):
self.id = key
self.connectedTo = {}
def addNeighbor(self, nbr, weight=0):
self.connectedTo[nbr] = weight
def __str__(self):
return str(self.id) + ' connectedTo: ' \
+ str([x.id for x in self.connectedTo])
def getConnections(self):
return self.connectedTo.keys()
def getId(self):
return self.id
def getWeight(self, nbr):
return self.connectedTo[nbr]
class Graph:
"""计算机数据结构-图"""
def __init__(self):
self.vertList = {}
self.numVertices = 0
def addVertex(self, key):
# https://blog.csdn.net/qilei2010博主注:
# 该书中此方法不够严谨,未判断该key是否已存在
# 这里我加上了if else
if key not in self.vertList:
self.numVertices = self.numVertices + 1
newVertex = Vertex(key)
self.vertList[key] = newVertex
return newVertex
else:
return self.vertList[key]
def getVertex(self, n):
if n in self.vertList:
return self.vertList[n]
else:
return None
def __contains__(self, n):
return n in self.vertList
def addEdge(self, f, t, cost=0):
if f not in self.vertList:
nv = self.addVertex(f)
if t not in self.vertList:
nv = self.addVertex(t)
self.vertList[f].addNeighbor(self.vertList[t], cost)
def getVertices(self):
return self.vertList.keys()
def __iter__(self):
return iter(self.vertList.values())
def listToGraph(mylist):
graph = Graph()
for i in mylist:
graph.addVertex(i)
for i, v in enumerate(mylist):
if i - 1 >= 0:
left = mylist[i - 1]
graph.addEdge(v, left)
if i + 1 <= len(mylist) - 1:
right = mylist[i + 1]
graph.addEdge(v, right)
return graph
mylist = [1, 7, 9, 10, 6, 4]
graph = listToGraph(mylist)
for key in graph.getVertices():
print(graph.getVertex(key))
代码的输出:
1 connectedTo: [7]
7 connectedTo: [1, 9]
9 connectedTo: [7, 10]
10 connectedTo: [9, 6]
6 connectedTo: [10, 4]
4 connectedTo: [6]