图抽象数据类型的Python实现
class Vertex:
def __init__(self, key):
self.id = key
self.connectedTo = {}
def addNeighbor(self, nbr, weight=0): #自己,邻居,权重
self.connectedTo[nbr] = weight #把nbr赋值给权重
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.vertexList = {} #顶点列表为空
self.numVertices = 0 #顶点数量为0
def addVertex(self, key): #添加顶点
self.numVertices = self.numVertices + 1
newVertex = Vertex(key)
self.vertexList[key] = newVertex
return newVertex
def getVertex(self, n):
if n in self.vertexList[n]: #通过key查找顶点
return self.vertexList[n]
else:
return None
def __contains__(self, n):
return n in self.vertexList
#判断from顶点和To顶点是否在这个图里,没有则添加
def addEdge(self, f, t,cost=0): #添加边
if f not in self.vertexList: #不存在的顶点先添加
nv = self.addVertex(f)
if t not in self.vertexList:
nv = self.addVertex(t)
#调用起始顶点的方法添加邻接边
self.vertexList[f].addNeighbor(self.vertexList[t], cost)
def __iter__(self):
return iter(self.vertexList.values())
图的应用:词梯问题(Word Ladder)
- 由"爱丽丝梦游仙境奇境"的作者Lewis Carroll在1878年所发明的单词游戏
- 从一个单词演变到另一个单词,其中的过程可以经过多个中间单词
- 要求是相邻两个单词之间差异只能是1个字母
- 例:FOOL >> POOL >> POLL
- 找到最短的单词变换序列
- 采用图来解决问题的步骤如下
- 将可能的单词之间的演变关系表达为图
- 采用"广度优先搜索BFS”, 来搜寻从开始单词到结束单词之间的所有有效路径
- 选择其中最快到达目标单词的路径
构建单词关系图
- 将单词作为顶点的标识Key
- 如果两个单词之间仅相差一个字母,就在它们之间设一条边
下图是从FOOL到SAGE的词梯解,所用的图是无向图,边没有权重
- FOOL到SAGE的每条路径都是一个解
构建单词关系图方法
可以通过不同的算法来构建(以4个字母的单词表为例)
- 首先是将所有单词作为顶点加入图中,再设法建立顶点之间的边
建立边的最直接算法,是对每个顶点(单词),与其他所有单词进行比较,如果相差一个字母,则建立一条边
- 时间复杂度是)(n**2),对于所有4个字母的5110个单词,需要超过2600万次比较
改进的算法是创建大量的桶,每个桶可以存放若干单词
- 桶标记是去掉一个字母,通配符"_"占空的单词
所有匹配标记的单词都放到这个桶里
-所有单词就位后,再在同一个桶的单词之间建立边即可
采用字典建立桶
def buildGraph(wordFile):
d = {}
g = Graph()
wfile = open(wordFile, 'r')
# 创建相差一个字母的桶
for line in wfile:
word = line[:-1]
for i in range(len(word)):
buckets = word[:i] + '_' + word[i+1:]
if bucket in d:
d[bucket].append(word)
else:
d[bucket] = [word]
#为每个相同的桶添加顶点和边
for bucket in d.keys():
for word1 in d[bucket]:
for word2 in d[bucket]:
if word1 != word2:
g.addEdge(word1, word2)
return g
- 文件需要下载