数据结构与算法

图抽象数据类型的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
  • 文件需要下载
如果采用邻接矩阵表示这个单词关系图,则需要2600万个矩阵单元
单词关系图是一个非常稀疏的图
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Leopold·Lin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值