广度优先算法(BFS)的python实现与词梯问题

背景:词梯问题

从一个单词演变为另一个单词,其中的过程可以经过多个中间单词,要求是相邻两个单词之间差异只能是1个字母。如FOOL变为SAGE:FOOL >> POOL >> POLL >> POLE >> PALE >> SALE >> SAGE。
我们的目标是找到最短的单词变换序列,采用图来解决这个问题的步骤如下:将可能的单词之间的演变关系表达为图,采用广度优先搜索BFS,来搜寻从开始单词到结束单词之间的所有有效路径,选择其中最快到达目标单词的路径。
从FOOL到SAGE的词梯解,所用的图是无向图,边没有权重,FOOL到SAGE的每条路径都是一个解。广度优先算法(BFS)的python实现与词梯问题_第1张图片
注意:构建单词关系图,若包含较多单词时,采用邻接矩阵来表示时会是一个非常稀疏的图,单元利用率仅为百分之几。
采用字典建立词梯桶

def buildGraph(wordFile):
    d = {}
    g = Graph()
    wfile = open(wordFile,'r')
    for line in wfile:
        word = line[:-1]
        for i in range(len(word)):  # 4字母单词可属于4个桶
            bucket = 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

广度优先算法(BFS)

BFS是搜索图的最简单算法之一,也是其它一些重要的图算法的基础。
算法思路:给定图G,以及开始搜索的起始顶点s。BFS搜索所有从s可到达顶点的边,而且在达到更远的距离k+1的顶点之前,BFS会找到全部距离为k的顶点。可以想象为以s为根,构建一棵树的过程,从顶部向下逐步增加层次。广度优先搜索能保证在增加层次之前,添加了所有兄弟节点到树中。
以词梯问题为例:说明广度优先算法的过程:

从起始顶点s开始,作为刚发现的顶点,标注为灰色(已发现),距离为0,前驱为None,加入队列,接下来是个循环迭代过程:从队首取出一个顶点作为当前顶点;遍历当前顶点的邻接顶点,如果是尚未发现的白色顶点,则将其颜色改为灰色(已发现),距离增加1,前驱顶点为当前顶点,加入到队列中;遍历完成后,将当前顶点设置为黑色(已探索过),循环回到步骤1的队首取当前顶点。
广度优先算法(BFS)的python实现与词梯问题_第2张图片

### 广度优先算法
def bfs(g,start):
    start.setdistance(0)
    start.setpred(None)
    vertqueue=Queue()
    vertqueue.enqueue(start)
    while (vertqueue.size()>0):  #取队首为当前节点
        currentvert=vertqueue.dequeue()  #遍历临接顶点
        for nbr in currentvert.getConnections():
            if (nbr.getcolor()=='white'):
                nbr.setcolor('gray')
                nbr.setdistance(currentvert.getdistance()+1)
                nbr.setpred(currentvert)
                vertqueue.enqueue(nbr)
        currentvert.setcolor('black')  #设置当前顶点为黑色

def tranverse(y):  #回溯函数来确定特定单词到任何单词顶点的最短词梯
    x=y
    while (x.getpred()):
        print(x.getId())
        x=x.getpred()
    print (x.getId())

wordgraph=buildGraph(fourletterwords.txt)
bfs(wordgraph,wordgraph.getVertex('fool'))
tranverse(wordgraph.getvertex('sale'))

算法分析:
(1)BFS算法主体是两个循环的嵌套,while循环对每个顶点访问一次,所以是O(|V|),而嵌套在while中的for,由于每条边只有在其起始顶点u出队的时候才会被检查一次,而每个顶点最多出队一次,所以边最多被检查1次,一共是0(|E|),综合起来BFS的时间复杂度为0(|V|+|E|)
(2)词梯问题还包括两个部分算法:建立BFS树之后,回溯顶点到起始顶点的过程,最多为0(|V|);创建单词关系图也需要时间,最多为O(|V|^2)。

你可能感兴趣的:(数据结构与算法-python版)