【有限状态机】- FSM详细讲解 【附Autoware有限状态机模型代码讲解】

参考博客:
(1)FSM(有限状态机)
(2)关于有限状态机(FSM)的一些思考
(3)状态设计模式

1 状态机简介

有限状态机FSM:有限个状态以及在这些状态之间的转移和动作等行为的数学模型。

状态机思维:将一个事件分成多个完整的状态,每个状态通过输入和输出进入下一个状态。

优点:可以把模型的多状态和多状态之间的转换条件解耦,降低程序耦合度,让程序维护变的更加容易

FSM术语:state、transition、action、transition condition

2 FSM术语

2.1 状态 State

将一件事拆分为多件事,为每一件事赋予一个名字,这个名字就被称为FSM中的状态。因其状态有限,所以FSM被称为有限状态机

  • 风扇:划分为关、一档、二挡、三挡等状态
  • 电梯门:划分为关闭、正在开启、开启、正在关闭
2.2 状态转移

状态转移:一个状态执行了某些动作转变为另一个状态的过程

2.3 转移条件 Event

在某个状态下,达到了某个转移条件,才会按照状态机的转移流程转移到下一状态,并执行相应的动作

2.4 动作 Action

当转变为一个新状态时,在这个状态下需要做的事情,称为动作

3 有限状态机的实现方式

实现方式适用场景优点缺点
分支逻辑法适用于条件简单,状态固定,没有新增和扩展的需求状态机代码直译,简单直接,状态逻辑比较集中,容易查看对于较复杂的状态机,这种方式容易遗漏或者写错。大量的if-else和switch-case代码分支判断逻辑,可读性和可扩展性比较差,对新增和修改的场景容易引入bug
查表法通过二维数组来表达状态机,适用于复杂状态机,执行动作比较固定和简单的场景,比如游戏这种状态比较多的场景就适合用查表法相对于分支逻辑的实现方式,查表法的代码实现更加清晰,可读性和可维护性更好遇到比较复杂的动作,就无法通过简单的二维数组表示了,有一定的局限性
状态模式对于状态并不多、状态转移也比较简单,但事件触发执行的动作包含的业务逻辑可能比较复杂的状态机来说,我们首选这种实现方式代码结构更清晰,可以规避过多的分支逻辑判断,代码可维护性更高状态模式会引入很多状态类,如果状态颗粒度控制不好,会导致状态类爆炸问题;另外逻辑比较分散,集中在状态类中,无法在一个地方整体看出整个状态机的逻辑
3.1 示例FSM

三种状态:未支付、未收货、完成
两种事件:支付、收货
状态的流转即动作:支付后状态为未收货,收货后状态为完成

支付状态枚举

// 支付状态枚举
enum PayState {// 待支付UNPAY = 0,// 待收货UNRECEIVE = 1,// 完成FINAL = 2,// 错误ERROR = 3,
};

支付事件枚举

// 支付事件枚举
enum PayEvent {// 支付Pay = 0,// 收货RECEIVE = 1,
};
3.2 分支逻辑法
#include <iostream>using namespace std;// 支付状态枚举
enum PayState {// 待支付UNPAY = 0,// 待收货UNRECEIVE = 1,// 完成FINAL = 2,// 错误ERROR = 3,
};// 支付事件枚举
enum PayEvent {// 支付PAY = 0,// 收货RECEIVE = 1,
};class PayStateMachine {private:PayState payState;public:PayStateMachine() {payState = PayState::UNPAY;}void executeEvent(PayEvent payEvent) {switch (payEvent) {// 支付行为发生:未支付 -> 待收货case PAY:if (this->payState != PayState::UNPAY) {cout << "商铺不是【未支付】状态,请核验" << endl;this->payState = PayState::ERROR;break;} this->payState = PayState::UNRECEIVE;break;// 收货行为发生:待收货 -> 完成case RECEIVE:if (this->payState != PayState::UNRECEIVE) {cout << "商铺不是【未收货】状态,请核验" << endl;this->payState = PayState::ERROR;break;}this->payState = PayState::FINAL;break;default:cout << "未设置的行为" << endl;break;}}PayState getCurrentState() {return this->payState;}
};int main() {PayStateMachine payStateMachine;cout << "当前状态为:" << payStateMachine.getCurrentState() << endl;payStateMachine.executeEvent(PayEvent::RECEIVE);cout << "当前状态为:" << payStateMachine.getCurrentState() << endl;return 0;
}

运行结果:

当前状态为:0
商铺不是【未收货】状态,请核验
当前状态为:3

3.3 查表法

将状态和事件形成一个二维矩阵表,将结果态放入其中

UNPAYUNRECEIVEFINAL
PAY状态转为UNRECEIVEERRORERROR
RECEIVEERROR状态转为FINALERROR

将结果态转为一个二维数组进行存储,用的时候使用状态和事件枚举的value值作为索引,获取结果态

#include <iostream>
#include <vector>
using namespace std;// 支付状态枚举
enum PayState {// 待支付UNPAY = 0,// 待收货UNRECEIVE = 1,// 完成FINAL = 2,// 错误ERROR = 3,
};// 支付事件枚举
enum PayEvent {// 支付PAY = 0,// 收货RECEIVE = 1,
};class PayStateMachine {public:// 初始化PayStateMachine() {currentPayState = PayState::UNPAY;}// 使用状态和事件枚举的value值作为索引,获取结果态void executeEvent(PayEvent payEvent) {this->currentPayState = payStateTable[this->currentPayState][payEvent];}// 获取当前状态PayState getCurrentState() {return this->currentPayState;	}private:// 当前状态PayState currentPayState;// 将结果态转为一个二维数组进行存储vector<vector<PayState>> payStateTable = {{UNRECEIVE, ERROR, ERROR},{ERROR, FINAL, ERROR}};
};int main()
{PayStateMachine payStateMachine;cout << "当前状态为:" << payStateMachine.getCurrentState() << endl;payStateMachine.executeEvent(PayEvent::PAY);cout << "当前状态为:" << payStateMachine.getCurrentState() << endl;payStateMachine.executeEvent(PayEvent::RECEIVE);cout << "当前状态为:" << payStateMachine.getCurrentState() << endl;return 0;
}

运行结果:

当前状态为:0
当前状态为:1
当前状态为:2
3.4 状态模式

状态模式,定义状态接口,并将行为规定为抽象方法,实现对应三种状态以及行为方法(实现状态流转逻辑)。

定义状态机,并依赖状态接口。

同时,每个具体的状态又依赖状态机。

即状态机和各个状态类之间是双向依赖关系,因为每个状态需要依靠状态机修改状态

状态模式将每个状态的实现都封装在一个类中,每个状态类的实现相对独立,使得添加新状态或修改现有状态变得更加容易,避免了使用大量的条件语句来控制对象的行为。但是如果状态过多,会导致类的数量增加,可能会使得代码结构复杂。

状态模式基本结构

  • State:定义一个接口,用于封装与Context的一个特定状态相关的行为
  • ConcreteState(具体状态): 负责处理Context在状态改变时的行为, 每一个具体状态子类实现一个与Context的一个状态相关的行为。
  • Context(上下文): 维护一个具体状态子类的实例,这个实例定义当前的状态

在这里插入图片描述

#include <iostream>
#include <vector>
#include <string>// 状态接口
class State {
public:virtual std::string handle() = 0;  // 处理状态的方法
};// 具体状态类
class OnState : public State {
public:std::string handle() override {return "Light is ON";}
};class OffState : public State {
public:std::string handle() override {return "Light is OFF";}
};class BlinkState : public State {
public:std::string handle() override {return "Light is Blinking";}
};
// 上下文类
class Light {
private:State* state;  // 当前状态
public:Light() : state(new OffState()) {}  // 初始状态为关闭void setState(State* newState) {  // 设置新的状态delete state;  // 释放之前的状态对象state = newState;}std::string performOperation() {  // 执行当前状态的操作return state->handle();}~Light() {delete state;  // 释放内存}	
};int main() {// 读取要输入的命令数量int n;std::cin >> n;std::cin.ignore();  // 消耗掉整数后的换行符// 创建一个Light对象Light light;// 处理用户输入的每个命令for (int i = 0; i < n; i++) {// 读取命令并去掉首尾空白字符std::string command;std::getline(std::cin, command);// 根据命令执行相应的操作if (command == "ON") {light.setState(new OnState());} else if (command == "OFF") {light.setState(new OffState());} else if (command == "BLINK") {light.setState(new BlinkState());} else {// 处理无效命令std::cout << "Invalid command: " << command << std::endl;}// 在每个命令后显示灯的当前状态std::cout << light.performOperation() << std::endl;}return 0;
}

4 Autoware有限状态机代码解析

state_machine.h

#ifndef STATE_MACHINE_H
#define STATE_MACHINE_H#include <memory>
#include <iostream>namespace state_machine
{
// 定义一个枚举类StateList,表示车辆的不同状态
enum class StateList : int32_t
{MOVE_FORWARD,           // 车辆向前移动TRAFFIC_LIGHT_STOP,     // 遇到红灯停车LANE_CHANGE,            // 车辆变更车道STOP_SIGN_STOP,         // 遇到停车标志停车OBSTACLE_AVOIDANCE,     // 避障MISSION_COMPLETE = 100, // 任务完成EMERGENCY = -1,         // 紧急情况 
};
// 定义一个枚举类TrafficLight,表示交通信号灯的状态
enum class TrafficLight : int32_t
{RED,     // 红灯GREEN,   // 绿灯UNKNOWN, // 未知
};
// 定义一个枚举类ChangeFlag,表示车辆变更车道的方向
enum class ChangeFlag : int32_t
{straight,     // 直行right,        // 向右变更车道left,         // 向左变更车道unknown = -1, // 未知方向
};
// 用于将枚举类类型转换为整数类型
// 可以将枚举类的实例转换为整数类型,便于进行数值计算或其他整数相关的操作
template <class T>
typename std::underlying_type<T>::type enumToInteger(T t)
{return static_cast<typename std::underlying_type<T>::type>(t);
}// Forward Decralation
class StateContext;// abstract class for states
class BaseState
{
public:virtual ~BaseState() = default;                 // 确保子类可以正确地删除基类对象virtual void update(StateContext *context) = 0; // 用于更新状态virtual int32_t getStateName()                  // 返回当前状态的名称{return 0;};virtual std::unique_ptr<std::string> getStateNameString() // 返回当前状态的名称字符串{return 0;};
};// State : MOVE_FORWARD
class StateMoveForward : public BaseState
{
public:// 更新状态逻辑void update(StateContext *context) override;// 获取状态名称(整数表示)int32_t getStateName() override{return enumToInteger(StateList::MOVE_FORWARD);}// 获取状态名称(字符串表示)std::unique_ptr<std::string> getStateNameString() override{return std::unique_ptr<std::string>(new std::string("MOVE_FORWARD"));}// 静态方法,用于创建 StateMoveForward 对象static std::unique_ptr<BaseState> create(){return std::unique_ptr<BaseState>(new StateMoveForward);};private:StateMoveForward() = default;
};// State : TRAFFIC_LIGHT_STOP
class StateTrafficLightStop : public BaseState
{
public:// 更新状态逻辑void update(StateContext *context) override;// 获取状态名称(整数表示)int32_t getStateName() override{return enumToInteger(StateList::TRAFFIC_LIGHT_STOP);}// 获取状态名称(字符串表示)std::unique_ptr<std::string> getStateNameString() override{return std::unique_ptr<std::string>(new std::string("TRAFFIC_LIGHT_STOP"));}// 静态方法,用于创建 StateTrafficLightStop 对象static std::unique_ptr<BaseState> create(){return std::unique_ptr<BaseState>(new StateTrafficLightStop);};private:StateTrafficLightStop() = default;
};// State : LANE_CHANGE
class StateLaneChange : public BaseState
{
public:// 更新状态逻辑void update(StateContext *context) override;// 获取状态名称(整数表示)int32_t getStateName() override{return enumToInteger(StateList::LANE_CHANGE);}// 获取状态名称(字符串表示)std::unique_ptr<std::string> getStateNameString() override{return std::unique_ptr<std::string>(new std::string("LANE_CHANGE"));}// 静态方法,用于创建 StateLaneChange 对象static std::unique_ptr<BaseState> create(){return std::unique_ptr<BaseState>(new StateLaneChange);};private:StateLaneChange() = default;
};// State : STOP_SIGN_STOP
class StateStopSignStop : public BaseState
{public:// 更新状态逻辑void update(StateContext *context) override;// 获取状态名称(整数表示)int32_t getStateName() override{return enumToInteger(StateList::STOP_SIGN_STOP);}// 获取状态名称(字符串表示)std::unique_ptr<std::string> getStateNameString() override{return std::unique_ptr<std::string>(new std::string("STOP_SIGN_STOP"));}// 静态方法,用于创建StateStopSignStop对象static std::unique_ptr<BaseState> create(){return std::unique_ptr<BaseState>(new StateStopSignStop);};private:StateStopSignStop() = default;
};// State : Obstacle Avoidance
class StateObstacleAvoidance : public BaseState
{public:void update(StateContext *context) override;int32_t getStateName() override{return enumToInteger(StateList::STOP_SIGN_STOP);}std::unique_ptr<std::string> getStateNameString() override{return std::unique_ptr<std::string>(new std::string("OBSTACLE_AVOIDANCE"));}static std::unique_ptr<BaseState> create(){return std::unique_ptr<BaseState>(new StateObstacleAvoidance);};private:StateObstacleAvoidance() = default;
};// State : EMERGENCY
class StateEmergency : public BaseState
{
public:void update(StateContext *context) override;int32_t getStateName() override{return enumToInteger(StateList::EMERGENCY);}std::unique_ptr<std::string> getStateNameString() override{return std::unique_ptr<std::string>(new std::string("EMERGENCY"));}static std::unique_ptr<BaseState> create(){return std::unique_ptr<BaseState>(new StateEmergency);};private:StateEmergency() = default;
};// State : MISSION_COMPLETE
class StateMissionComplete : public BaseState
{
public:void update(StateContext *context) override;int32_t getStateName() override{return enumToInteger(StateList::MISSION_COMPLETE);}std::unique_ptr<std::string> getStateNameString() override{return std::unique_ptr<std::string>(new std::string("MISSION_COMPLETE"));}static std::unique_ptr<BaseState> create(){return std::unique_ptr<BaseState>(new StateMissionComplete);};private:StateMissionComplete() = default;
};
// 包含状态机当前状态的上下文对象,它包含了当前状态、交通灯颜色和车辆变更车道等信息
class StateContext
{
public:StateContext(): state_(StateMoveForward::create()), light_color_(TrafficLight::UNKNOWN), change_flag_(ChangeFlag::unknown){};// 设置状态机当前状态void setState(std::unique_ptr<BaseState> newState){state_ = std::move(newState);};// 更新状态机状态void update(){state_->update(this);}// 设置交通灯颜色void setLightColor(const int32_t &msg){light_color_ = static_cast<TrafficLight>(msg);}// 设置变道方向void setChangeFlag(const int32_t &msg){change_flag_ = static_cast<ChangeFlag>(msg);}// 获取当前交通灯颜色TrafficLight getLightColor() const{return light_color_;}// 获取当前变道方向ChangeFlag getChangeFlag() const{return change_flag_;}// 获取当前状态机的整数表示状态名称int32_t getCurrentState() const{return state_->getStateName();}// 获取当前状态机的字符串表示状态名称std::unique_ptr<std::string> getCurrentStateString() const{return state_->getStateNameString();}private:std::unique_ptr<BaseState> state_;TrafficLight light_color_;ChangeFlag change_flag_;
};}  // state_machine
#endif  // STATE_MACHINE_H

state_machine.cpp

#include "state_machine.h"namespace state_machine
{
void StateTrafficLightStop::update(StateContext *context)
{// 如果交通灯颜色为绿色,表示可以继续行驶,将状态机转移到StateMoveForward状态if (context->getLightColor() == TrafficLight::GREEN)context->setState(StateMoveForward::create());
}void StateMoveForward::update(StateContext *context)
{// 如果交通灯颜色为红色,表示需要停车,将状态机转移到 StateTrafficLightStop 状态if (context->getLightColor() == TrafficLight::RED)context->setState(StateTrafficLightStop::create());// 如果变化标志为右转或左转,将状态机转移到 StateLaneChange 状态if(context->getChangeFlag() == ChangeFlag::right || context->getChangeFlag() == ChangeFlag::left)context->setState(StateLaneChange::create());
}void StateLaneChange::update(StateContext *context)
{// 如果变化标志为直行,将状态机转移到 StateMoveForward 状态if(context->getChangeFlag() == ChangeFlag::straight)context->setState(StateMoveForward::create());
}void StateStopSignStop::update(StateContext *context)
{// stop sign stop
}void StateMissionComplete::update(StateContext *context)
{// Mission complete
}void StateEmergency::update(StateContext *context)
{// Emergency
}void StateObstacleAvoidance::update(StateContext *context)
{// Obstacle Avoidance
}}  // state_machine

有限状态机原理及三种模式代码实现如上,错误之处望读者指正。

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

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

相关文章

2024年最新最全Vue3开源后台管理系统复盘总结

在现代前端开发中&#xff0c;搭建一个高效、灵活、易用的后台管理系统并不容易。然而&#xff0c;Vue3 的出现为我们提供了一个备受瞩目的选择。作为一个现代化的前端框架&#xff0c;Vue3 具有众多优点&#xff0c;能够帮助开发者快速搭建企业级中后台产品原型。 今天&#…

iphoneX系统的参数

1. 2. 3. 4. 5.相关的网址信息 Apple iPhone X 規格、价格和评论 | Kalvo Apple iPhone X 規格、价格和评论 | Kalvo

UOS、Linux下的redis的详细部署流程(适用于内网)

提示&#xff1a;适用于Linux以及UOS等内外网系统服务器部署。 文章目录 一.上传离线包二.部署基本环境三.解压并安装redis四.后台运行redis五.uos系统可能遇到的问题六.总结 一.上传离线包 1.自己去Redis官网下载适配自己部署系统的redis安装包。 2.通过文件传输工具&#xf…

Rust使用原始字符串字面量实现Regex双引号嵌套双引号正则匹配

rust使用Regex实现正则匹配的时候&#xff0c;如果想实现匹配双引号&#xff0c;就需要使用原始字符串字面量&#xff0c;不然无法使用双引号嵌套的。r#"..."# 就表示原始字符串字面量。 比如使用双引号匹配&#xff1a; use regex::Regex;fn main() {println!(&qu…

快速幂算法在Java中的应用

引言&#xff1a; 在计算机科学和算法领域中&#xff0c;快速幂算法是一种用于高效计算幂运算的技术。在实际编程中&#xff0c;特别是在处理大数幂运算时&#xff0c;快速幂算法能够显著提高计算效率。本文将介绍如何在Java中实现快速幂算法&#xff0c;并给出一些示例代码和应…

151 shell编程,正则表达式,在C语言中如何使用正则表达式

零&#xff0c;坑点记录&#xff1a;bash 和 dash 的区别&#xff0c;导致的坑点 查看当前用的shell 是啥&#xff0c;用的是/bin/bash hunandedehunandede-virtual-machine:~$ echo $SHELL /bin/bash 当shell 脚本运行的时候&#xff08;后面会学到方法&#xff0c;这里是最…

全局UI方法-弹窗一警告弹窗(AlertDialog)

1、描述 显示警告弹窗组件&#xff0c;可设置文本内容与响应回调。 2、属性 名称参数类型参数描述showAlertDialogParamWithConfirm | AlertDialogParamWithButtons定义并显示AlertDialog组件。 2.1、AlertDialogParamWithConfirm对象说明&#xff1a; 参数名称参数类型必填…

『Apisix安全篇』探索Apache APISIX身份认证插件:从基础到实战

&#x1f680;『Apisix系列文章』探索新一代微服务体系下的API管理新范式与最佳实践 【点击此跳转】 &#x1f4e3;读完这篇文章里你能收获到 &#x1f6e0;️ 了解APISIX身份认证的重要性和基本概念&#xff0c;以及如何在微服务架构中实施API安全。&#x1f511; 学习如何使…

FreeRTOS(三)

第二部分 事件组 一、事件组的简介 1、事件 事件是一种实现任务间通信的机制&#xff0c;主要用于实现多任务间的同步&#xff0c;但事件通信只能是事件类型的通信&#xff0c;无数据传输。其实事件组的本质就是一个整数(16/32位)。可以是一个事件发生唤醒一个任务&#xff…

ClickHouse初体验

1.clickHouse是啥&#xff1f; ClickHouse 是俄罗斯的 Yandex 于 2016 年开源的列式存储数据库(DBMS)&#xff0c;使用 C语言编写&#xff0c;主要用于在线分析处理查询(OLAP)&#xff0c;能够使用SQL查询实时生成分析数据报告 2.clickHouse的特点 2.1列式存储 对于列的聚合&…

城市内涝排水新模式:慧天[HTWATER]

慧天[HTWATER]软件&#xff1a;慧天排水数字化分析平台针对城市排水系统基础设施数据管理的需求&#xff0c;以及水文、水力及水质模拟对数据的需求&#xff0c;实现了以数据库方式对相应数据的存储。可以对分流制排水系统及合流制排水系统进行地表水文、管网水力、水质过程的模…

Transformers 直观解释——不仅是如何工作,而且为什么工作得这么好

输入序列如何到达Attention模块 注意力模块存在于编码器堆栈中的每个编码器中&#xff0c;以及解码器堆栈中的每个解码器中。我们将首先放大编码器的注意力。 Attention in the Encoder&#xff1a; 举个例子&#xff0c;假设我们正在研究一个英语到西班牙语的翻译问题&…

【旅游】泉州攻略v1.0.0

一、泉州古城 泉州市距离深圳大约520公里&#xff0c;从深圳北站出发&#xff0c;高铁大约3小时30分。 到达泉州西站后&#xff0c;往东南方向大约8公里&#xff0c;就可以到达主要的旅游景点泉州古城。 古城很适合使用一天玩耍&#xff0c;核心路线如下&#xff1a; 一路的景…

C++ STL教程

C STL教程 文章目录 C STL教程1.1 std::vector1.1.1vector的定义1.1.2vector容器的初始化1.1.3vector容器内元素的访问和修改1.1.4vector中的常用函数 1.2 std::string1.2.1string的定义1.2.2string的初始化1.2.3string中元素的访问和修改1.2.4string中连接字符串1.2.5string中…

AtCoder Beginner Contest 337 A - E

A - Scoreboard 大意 高桥队和青木队进行了场比赛&#xff0c;给出每场比赛中高桥队和青木队的积分&#xff0c;问最后谁总分更高或平局。 思路 统计总分比较即可。 代码 #include<iostream> using namespace std; int main(){int n, a0, b0;cin >> n;while(…

介绍部署esxi8.0产品的方式

什么是esxi esxi的中文叫裸机虚拟机管理器 ESXi是由VMware公司开发的一种裸机虚拟机管理器&#xff0c;全称为VMware ESXi。 ESXi是一种虚拟化技术&#xff0c;专门设计用于在物理服务器上运行虚拟机&#xff0c;它的主要特点是能够最大限度地降低硬件配置要求并简化部署过程…

vcf文件可以用excel打开吗?四种解决方案

vcf文件可以用excel打开吗&#xff1f; 当然可以。 一、VCF文件简介 VCF&#xff08;vCard&#xff09;文件是一种用于存储联系人信息的文件格式。它通常包含姓名、电话号码、电子邮件地址、地址等详细信息。VCF文件在多种设备和操作系统中广泛使用&#xff0c;特别是在电子邮…

2024全国水科技大会【高峰对话】北京排水集团(附部分报告题目)

北京排水集团坚持“服务社会、造福百姓、企业利益与公众利益高度一致”的宗旨&#xff0c;充分认知自身在地区经济发展中的社会责任&#xff0c;以满足政府与公众对公用事业企业服务的需求为首要任务&#xff0c;通过“现代化的队伍、现代化的手段、现代化的设备和现代化的管理…

springBoot+ureport报表引擎

UReport是一款基于单元格迭代模型的纯Java中式报表引擎。它架构于Spring之上&#xff0c;因此与企业应用具有良好的集成能力。UReport提供了基于Eclipse插件与基于网页的两种报表模版设计方式&#xff0c;采用类Excel报表模版设计风格&#xff0c;简单、易上手&#xff0c;可在…

数据结构和算法:搜索

二分查找 二分查找&#xff08;binary search&#xff09; 是一种基于分治策略的高效搜索算法。它利用数据的有序性&#xff0c;每轮缩小一半搜索范围&#xff0c;直至找到目标元素或搜索区间为空为止。 给定一个长度为 &#x1d45b; 的数组 nums &#xff0c;元素按从小到大…