广度优先搜索(Breadth First Search, BFS)算法

news2024/11/15 15:44:32

广度优先搜索(Breadth First Search, BFS)

广度优先搜索是一种盲目搜索算法,它认为所有状态(或者说结点)都是等价的,不存在优劣之分。
d0c1a07a723e01b393d4b0fe3b5f7e7c.gif
假如我们把所有需要搜索的状态组成一棵树来看,广搜就是一层搜完再搜下一层,直到找出目标结点,或搜完整棵树为止。

  1. 我们可以使用一个先进先出(First Input First Output, FIFO)的队列来存放待搜索的状态,这个队列可以给它一个名称叫开放队列,也有人把它叫做开放列表(Open List)。
  2. 然后还需要把所有已搜索过的状态记录下来,以确保不会对已搜索过的状态作重复扩展,注意这里的扩展即为衍生出子状态,对应于拼图游戏来说就是空格移动了一格。
    由于每搜到一个状态,都需要拿着这个状态去已搜记录中查询是否有这个状态存在,那么已搜记录要使用怎样的存储方式才能适应这种高频率查找需求呢?
    假如我们使用数组来存储所有已搜记录,那么每一次查找都需要遍历整个数组。当已搜记录表的数据有 10 万条时,再去搜一个新状态,就需要做 10 万次循环来确定新状态是从来没有被搜索过的。显然这样做的效率是非常低的。
    一种高效的方法是哈希策略,**哈希表(Hash Table)**能通过键值映射直接查找到目标对象,免去遍历整个存储空间。在 Cocoa 框架中,已经有能满足这种键值映射的数据结构–字典。这里我没有再去实现一个哈希表,而是使用 NSMutableDictionary 来存放已搜记录。我们可以给这个存储空间起个名字叫关闭堆,也有人把它叫做关闭列表(Close List)。
  3. 搜索开始时,开放队列是空的,然后我们把起始状态入队,此时开放队列有了一个待搜索的状态,搜索循环开始。
  4. 每一次循环的目的,就是搜索一个状态。所谓搜索,前面已经讲过,可以通俗理解为就是比较。我们需要从开放队列中取出一个状态来,假如取出的状态是已经比较过了的,则放弃此次循环,直到取出一个从来没有比较过的状态。
  5. 拿着取出的新状态,与目标状态比较,如果一致,则说明路径已找到。为何说路径已找到了呢?因为每一个状态都持有一个父状态的引用,意思是它记录着自己是来源于哪一个状态衍生出来的,所以每一个状态都必然知道自己上一个状态是谁,除了开始状态。
  6. 找到目标状态后,就可以构建路径。所谓路径,就是从开始状态到目标状态的搜索过程中,经过的所有状态连起来组成的数组。我们可以从搜索结束的状态开始,把它放入数组中,然后把这个状态的父状态放入数组中,再把其祖先状态放入数组中,直到放入开始状态。如何识别出开始状态呢?当发现某个状态是没有父状态的,就说明了它是开始状态。最后算法把构建完成的路径作为结果返回。
  7. 在第 5 步中,如果发现取出的新状态并非目标状态,这时就需要衍生新的状态来推进搜索。调用生成子状态的方法,把产生的子状态入队,依次追加到队列尾,这些入队的子状态将会在以后的循环中被搜索。由于队列的 FIFO 特性,在循环进行过程中,将会优先把某个状态的子状态全部出列完后,再出列其子状态的子状态。入列和出列的两步操作决定了算法的搜索顺序,这里的操作实现了广度优先搜索。

广度优先搜索:

- (NSMutableArray *)search {
    if (!self.startStatus || !self.targetStatus || !self.equalComparator) {
        return nil;
    }
    NSMutableArray *path = [NSMutableArray array];
    
    // 关闭堆,存放已搜索过的状态
    NSMutableDictionary *close = [NSMutableDictionary dictionary];
    // 开放队列,存放由已搜索过的状态所扩展出来的未搜索状态
    NSMutableArray *open = [NSMutableArray array];
    
    [open addObject:self.startStatus];
    
    while (open.count > 0) {
        // 出列
        id status = [open firstObject];
        [open removeObjectAtIndex:0];
        
        // 排除已经搜索过的状态
        NSString *statusIdentifier = [status statusIdentifier];
        if (close[statusIdentifier]) {
            continue;
        }
        close[statusIdentifier] = status;
        
        // 如果找到目标状态
        if (self.equalComparator(self.targetStatus, status)) {
            path = [self constructPathWithStatus:status isLast:YES];
            break;
        }
        
        // 否则,扩展出子状态
        [open addObjectsFromArray:[status childStatus]];
    }
    NSLog(@"总共搜索了: %@个状态", @(close.count));
    return path;
}

构建路径:

/// 构建路径。isLast表示传入的status是否路径的最后一个元素
- (NSMutableArray *)constructPathWithStatus:(id<JXPathSearcherStatus>)status isLast:(BOOL)isLast {
    NSMutableArray *path = [NSMutableArray array];
    if (!status) {
        return path;
    }
    
    do {
        if (isLast) {
            [path insertObject:status atIndex:0];
        }
        else {
            [path addObject:status];
        }
        status = [status parentStatus];
    } while (status);
    return path;
}

0386e83d911c678d392eecae1555d96e.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1114016.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

旅游业媒体套餐7个诀窍助你轻松实现销售目标-华媒舍

旅游业是一个竞争激烈的行业&#xff0c;成功营销对于吸引客户和实现销售目标至关重要。借助媒体资源是一种有效的方式。本文将介绍7个诀窍&#xff0c;借助旅游业媒体套餐轻松实现销售目标。 1. 策划细致的新闻稿 新闻稿是介绍旅游产品和服务的重要工具。确保新闻稿中包含吸引…

【精选】2023网络安全学习路线 非常详细 推荐学习

关键词&#xff1a;网络安全入门、渗透测试学习、零基础学安全、网络安全学习路线 分享2套零基础、进阶学习网络安全/渗透测试教程 第一套是Web安全学习笔记 该笔记详细介绍了计算机网络协议、信息收集、常见漏洞、内网渗透、御用技术等等&#xff0c;全文全面成体系&#x…

京东店铺所有商品数据接口及店铺商品数据分析

获取京东店铺所有商品数据的接口是京东开放平台提供的接口&#xff0c;通过该接口可以获取店铺所有商品数据。 通过京东开放平台接口获取店铺所有商品数据的方法如下&#xff1a; 在开放平台注册成为开发者并创建一个应用&#xff0c;获取到所需的 App Key 和 App Secret 等信…

PHP 基础/练习

练习 成绩定级 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>成绩定级脚本</title> </…

Windows 事件日志监控

Windows 事件日志是记录 Microsoft 系统上发生的所有活动的文件&#xff0c;在 Windows 环境中&#xff0c;将记录系统上托管的系统、安全性和应用程序的事件&#xff0c;事件日志提供包含有关事件的详细信息&#xff0c;包括日期、时间、事件 ID、源、事件类型和发起它的用户。…

spring cloud Eureka集群模式搭建(IDEA中运行)

spring cloud Eureka集群模式搭建&#xff08;IDEA中运行&#xff09; 新建springboot 工程工程整体目录配置文件IDEA中部署以jar包形式启动总结 新建springboot 工程 新建一个springboot 工程&#xff0c;命名为&#xff1a;eureka_server。 其中pom.xml文件为&#xff1a; …

el-input无法输入的问题和表单验证失败问题(亲测有效)-开发bug总结4

大部分无法输入的问题&#xff1a;基本都是没有进行v-model双向数据绑定&#xff0c;这个很好解决。 本人项目中遇到的bug问题如下&#xff1a; 点击添加&#xff0c;表单内可输入用户名 和 用户姓名&#xff0c;但有时会偶发出现无法这两个input框里面无法输入内容。 原因&a…

使用 Rust 开发:以太坊与 Layer2 生态建设新趋势

Rust 是一种系统编程语言&#xff0c;以其出色的性能、内存安全和并发性而闻名&#xff0c;在区块链和 Web3 中广泛应用&#xff0c;大多数编程语言和开发框架都以 Rust 为核心&#xff0c;如 Polkadot、Solana、NEAR、Elrond&#xff08;现名 MultiversX&#xff09;、Hyperle…

探索房产小程序源码中的十大必备功能

作为房地产行业的专家&#xff0c;我们深知房产小程序在实现高效交易和提升用户体验方面的重要性。选择适合的房产小程序源码&#xff0c;关乎着您的平台能否脱颖而出。在本文中&#xff0c;我将为您揭示房产小程序中不可或缺的十大必备功能&#xff0c;助您确保您的小程序具备…

CSDN 使用体验:一路向上

使用CSDN已经很多年了&#xff0c;这些年我真的在这一平台上收获了很多&#xff0c;而这些年CSDN自身也在不断进步&#xff0c;一步步成长&#xff0c;尤其是在最近的使用过程中&#xff0c;我感受到了CSDN前所未有的包容性、全面性&#xff0c;并且收获成就感。 包容性 随着…

Linux 下 Java 安装字体方法

因上线访问图字体乱码了&#xff0c;因为在windows下设置的微软雅黑&#xff0c;linux默认是没有的&#xff0c;所以需要给jdk安装一个微软雅黑字体。按照步骤来&#xff0c;so easy&#xff01; 1&#xff09;首先找到windows下面的字体&#xff0c;不用去其他地方下了&#…

干货:电视机顶盒哪个牌子好?双11必看网络机顶盒排行榜

电视机顶盒是我们必不可少的&#xff0c;新手们在面对众多品牌和产品是难免疑惑电视机顶盒哪个牌子好&#xff0c;双十一买哪款电视机顶盒最实惠&#xff1f;我将给大家分享的是业内公认的网络机顶盒排行榜&#xff0c;想知道哪些电视盒子品牌最值得买&#xff0c;看这篇就足够…

【vue】使用less报错:显示this.getOptions is not a function

在vue-cli中使用 lang“less” 时报错&#xff1a; Module build failed: TypeError: this.getOptions is not a function at Object.lessLoader 原因&#xff1a;版本过高所致&#xff0c;所用版本为 解决&#xff1a;降低版本&#xff1a;npm install less-loader4.1.0 --s…

c: Queue Calling in Ubuntu

/*** file TakeNumber.h* author your name (geovindu)* brief * version 0.1* date 2023-10-20* * copyright Copyright (c) 2023 站在巨人的肩膀上 Standing on the Shoulders of Giants* */#ifndef TAKENUMBER_H #define TAKENUMBER_H#include <stdio.h> #include <…

绝了!!AI写作神器,自动写小说真的牛

宝子们&#xff0c;这个写小说的神器有点牛&#xff01;尊的是宝藏写作神器啊&#xff01;分分钟写出小说&#xff0c;就连作文&#xff0c;论文都能写&#xff0c;这也太神了吧&#xff01; 使用炒鸡简单&#xff01;新手都能用 输入文字后就能得到你需要的文章 还有超多功…

Kubernetes技术与架构-Ingress Controller

Ingress Controller控制器是实现Ingress对象的定义的组件&#xff0c;也即网关&#xff0c;负责Kubernetes集群内流量的分发&#xff0c;Kubernetes可以运行多个Ingress Controller控制器实例&#xff0c;不同的Ingress定义可以使用不同的Ingress Controller控制器实现&#xf…

插入排序(学习笔记)

插入排序 每一轮插入排序后的结果与打扑克牌取牌原理相似&#xff0c;将取到的牌插入到合适的位置&#xff0c;但在程序实现方面还是基于交换的算法。 它的基本思想是将一个记录插入到已经排好序的有序表中&#xff0c;从而一个新的、记录数增1的有序表。 import java.util.…

vlookup函数踩坑(wps)

使用wps的朋友看过来 vlookup函数踩坑&#xff0c;vlookup&#xff08;查找值&#xff0c;查找范围&#xff0c;返回值的索引&#xff0c;精确查找or模糊查找&#xff09; 我们要查找的数据的那一列&#xff0c;必须是查找范围的第一列&#xff01; 案例&#xff0c;看下面的…

使用guacamole进行WEB远程桌面连接

Apache Guacamole 是一个无客户端的远程桌面网关。它支持标准协议&#xff0c;如 VNC、RDP 和 SSH&#xff0c;甚至还支持k8s、telnet连接。它可以在任何有网络的地方连接上你的服务器和Windows主机。可以同时连接多个终端&#xff0c;并且能够无缝切换。本文采用docker进行部署…

4.9 多协议标记交换MPLS

思维导图&#xff1a; 前言&#xff1a; **4.9 多协议标记交换MPLS笔记** 1. **定义与背景**&#xff1a; - MPLS (多协议标记交换) 是一种由 IETF 开发的新协议。 - “多协议”意味着 MPLS 的上层可以使用多种协议。 - 该协议综合了多家公司的技术&#xff0c;如 C…