数据结构--宽度优先搜索

词梯问题的例子

使用图的 宽度优先算法 解决 词梯问题

词梯问题介绍:考虑这样一个任务:将单词 FOOL 转换成 SAGE。在解决词梯问题时,必须每次只替换一个字母,并且每一步的结果都必须是一个单词,而不能是不存在的词。

例子:
在这里插入图片描述

第一步:构建图,只有一个字母不同的单词连边

思路:
方法1:先将每一个单词赋予顶点对象。将每一个单词与其他单词对比,只相差一个字母的两个单词添加边。
但是这种办法复杂度太高,进行O(n^2)次比较。×
方法2:用词桶的办法。一边读单词,一边就把单词放到对应的桶里面,同一个桶里面的单词肯定是邻接的。
这样就不用做比较了。(其实这时候比较蕴含在,通配字符串是否存在于字典中,但是复杂度会小很多。)
在这里插入图片描述

# 词梯
from pythonds.graphs import Graph


def build_graph(file_name):
    g = Graph()
    f = open(file_name)
    buckets_dict = {}
    # 读取单词,并将其放入词桶
    for line in f.readlines():
        word = line[:-1]
        for i in range(len(word)):
            bucket = word[i] + '_' + word[i + 1:]
            if bucket in buckets_dict:
                buckets_dict[bucket].append(word)
            else:
                buckets_dict[bucket] = [word]
    # 创建图

    for b_list in buckets_dict.values():
        for w in b_list:
            for v in b_list:
                if w != v:
                    g.addEdge(w, v)
    return g

第二步:找到最短路径–宽度优先搜索BFS

(breadth first search)

  • 我先用算法形式,描述一遍代码过程:
    初始化:
    将开始点的pre设置为None,distance设置为0,入队。
    循环:
    出队一个点作为当前节点,标记为黑色。
    遍历其邻接表,如果nbr是白色,就将其标记为灰色,将其pre设置为当前节点,将其distance设置为当前顶点+1,并入队。
    以上循环直到队列为空。

评价:出队的顶点黑色;在队列里的灰色,还没入队的白色。

上述过程可以用一个树来表示,其实是建立了一棵宽度优先搜索树

书上的描述语言是这样的:
在这里插入图片描述

用图形来解释:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
下面是代码 dfs 函数:

def dfs(g, start):
    """
    g:要进行宽度优先搜索的图
    start:搜索的起始顶点
    """
    # 初始化
    # 先将g中所有顶点的颜色设置成白色
    [vert.setColor('white') for vert in g]
    q = Queue()
    start.setDistance(0)
    start.setPred(None)
    q.enqueue(start)
    while q.size() > 0:
        current_vert = q.dequeue()
        current_vert.setColor('black')
        for nbr in current_vert.getConnections():
            if nbr.getColor() == 'white':
                nbr.setColor('gray')
                nbr.setPred(current_vert)
                nbr.setDistance(current_vert.getDistance() + 1)
                q.enqueue(nbr)

第三步:找到fool转sage的最短词梯–回溯宽度优先搜索树

我们可以用从上面建立的宽度优先搜索树的任意节点开始,沿着pred回溯到根节点,来找到fool转换成任意单词的最短路径。

注意:我们设置了根节点的pred是None。

下面是回溯函数:

def traverse(x):
    """回溯"""
    print('distance:', x.getDistance())
    print('route:')
    while x.getPred():
        print('\t', x.getId())
        x = x.getPred()
    print('\t', x.getId())

最后:测试结果

# 创建图
words_graph = build_graph('words.txt')
# 建立宽度优先搜索树
dfs(words_graph, words_graph.getVertex('fool'))
# 回溯寻找路径
traverse(words_graph.getVertex('sage'))
distance: 6
route:
	 sage
	 sale
	 pale
	 pall
	 poll
	 pool
	 fool

注: 文本文件中单词顺序不同,创建的搜索树也可能不同。但是最短距离肯定是一样的,因为图是唯一的。

宽度优先搜索复杂度分析

while循环遍历的是队列元素,每个顶点就入队一次,出队一次,所以这个复杂度是O(V)。
for循环遍历每个顶点的邻接表,复杂度是O(E).
总的时间复杂度就是O(V+E)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值