【有限状态机】- 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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

对比HTTP与WebSocket

目录 对比HTTP与WebSocket1. HTTP协议概述2. WebSocket协议概述3. HTTP与WebSocket的区别4. 使用场景比较5. 性能比较6. 安全性比较7. 应用案例分析8. 总结与展望 对比HTTP与WebSocket 1. HTTP协议概述 1.1 HTTP的基本概念 HTTP&#xff08;Hypertext Transfer Protocol&…

基于Java实现宠物领养救助交流平台设计和实现

基于Java实现宠物领养救助交流平台设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 文末获取源码联…

腾讯云4核8g服务器多少钱?轻量和CVM收费价格表2024年最新

2024年腾讯云4核8G服务器租用优惠价格&#xff1a;轻量应用服务器4核8G12M带宽646元15个月&#xff0c;CVM云服务器S5实例优惠价格1437.24元买一年送3个月&#xff0c;腾讯云4核8G服务器活动页面 txybk.com/go/txy 活动链接打开如下图&#xff1a; 腾讯云4核8G服务器优惠价格 轻…

RabbitMQ简单介绍

什么是消息队列 消息队列是一种在应用程序之间传递消息的通信模式。它提供了一种异步的、可靠的方式来处理分布式系统中的消息传递。在消息队列中&#xff0c;消息发送者&#xff08;Producer&#xff09;将消息发送到队列&#xff08;Queue&#xff09;中&#xff0c;而消息接…

R语言 | 上下双向柱状图

1. 效果图 2. 代码 # 生成测试数据 difdata.frame(labelspaste0("pathway", 1:3),upc(30,15,1),downc(10,20,40) ) rownames(dif)dif$labels dif#变形 difreshape2::melt(dif) dif# 绘图 ggplot(dif, aes(xlabels, yifelse(variable"up", value, -value), …

ubuntu 中安装docker

1 资源地址 进入ubuntu官网下载Ubuntu23.04的版本的镜像 2 安装ubuntu 这里选择再Vmware上安装Ubuntu23.04.6 创建一个虚拟机&#xff0c;下一步下一步 注意虚拟机配置网络桥接&#xff0c;CD/DVD选择本地的镜像地址 开启此虚拟机&#xff0c;下一步下一步等待镜像安装。 3…

边缘计算迎来“量子飞跃”!支持抗量子密码,AMD推出FPGA新系列

3月6日&#xff0c;AMD宣布推出AMD Spartan™ UltraScale™ FPGA系列&#xff0c;这是AMD成本优化FPGA和自适应SoC广泛产品组合的最新成员。 距离1月22日&#xff0c;AMD推出业界首款符合VESA DisplayPort 2.1标准的FPGA和自适应SoC实现&#xff0c;也才过了一个多月的时间。 S…

【pytest、playwright】allure报告生成视频和图片

目录 1、修改插件pytest_playwright 2、conftest.py配置 3、修改pytest.ini文件 4、运行case 5、注意事项 1、修改插件pytest_playwright pytest_playwright.py内容如下&#xff1a; # Copyright (c) Microsoft Corporation. # # Licensed under the Apache License, Ver…

前端埋点全解及埋点SDK实现方式

一、什么是埋点 所谓“埋点”&#xff0c;是数据采集领域&#xff08;尤其是用户行为数据采集领域&#xff09;的术语&#xff0c;指的是针对特定用户行为或事件进行捕获、处理和发送的相关技术及其实施过程。比如用户某个icon点击次数、观看某个视频的时长等等。 埋点…

Day22 LeedCode:235.二叉搜索树的最近公共祖先 701.二叉搜索树的插入操作 450.删除二叉搜索树的结点

235. 二叉搜索树的最近公共祖先 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个结点 p、q&#xff0c;最近公共祖先表示为一个结点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&…

openGauss增量备份恢复

openGauss 增量备份恢复 openGauss 数据库自 2020 年 6 月 30 日发布以来&#xff0c;很多小伙伴都提到“openGauss 数据库是否有增量备份工具&#xff1f;“这么一个问题。 在 openGauss 1.0.0 版本的时候&#xff0c;关于这个问题的回答往往是&#xff1a;“Sorry…”&…

ClickHouse10-ClickHouse中Kafka表引擎

Kafka表引擎也是一种常见的表引擎&#xff0c;在很多大数据量的场景下&#xff0c;会从源通过Kafka将数据输送到ClickHouse&#xff0c;Kafka作为输送的方式&#xff0c;ClickHouse作为存储引擎与查询引擎&#xff0c;大数据量的数据可以得到快速的、高压缩的存储。 Kafka大家…

免费SSL证书和付费SSL证书的区别点

背景&#xff1a; 在了解免费SSL证书和付费SSL证书的区别之前&#xff0c;先带大家了解一下SSL证书的概念和作用。 SSL证书的概念&#xff1a; SSL证书就是基于http超文本传输协议的延伸&#xff0c;在http访问的基础上增加了一个文本传输加密的协议&#xff0c;由于http是明…

【SQL】1633. 各赛事的用户注册率(COUNT函数 表达式用法)

题目描述 leetcode题目&#xff1a;1633. 各赛事的用户注册率 Code select contest_id, round(count(*)/(select count(*) from Users)*100, 2) as percentage from Register group by contest_id order by percentage desc, contest_id ascCOUNT()函数 COUNT函数用法&#…

每日一题 --- 链表相交[力扣][Go]

链表相交 题目&#xff1a;面试题 02.07. 链表相交 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交**&#xff1a;** 题目数据 保证 整个链式结…

【每日力扣】452. 用最少数量的箭引爆气球与763. 划分字母区间

&#x1f525; 个人主页: 黑洞晓威 &#x1f600;你不必等到非常厉害&#xff0c;才敢开始&#xff0c;你需要开始&#xff0c;才会变的非常厉害。 452. 用最少数量的箭引爆气球 有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points &#xff0…

Chronos: 将时间序列作为一种语言进行学习

这是一篇非常有意思的论文&#xff0c;它将时间序列分块并作为语言模型中的一个token来进行学习&#xff0c;并且得到了很好的效果。 Chronos是一个对时间序列数据的概率模型进行预训练的框架&#xff0c;它将这些值标记为与基于transformer的模型(如T5)一起使用。模型将序列的…

阿里云ubuntu服务器搭建可视化界面

连接终端 最好初始化服务器的时候 不要以root权限创建 否则会出错 1更新软件: sudo apt-get update2安装ubuntu desktop : sudo apt-get install ubuntu-desktop3 配置ubuntu desktop并重启: sudo apt-get -f install sudo dpkg-reconfigure ubuntu-desktop sudo reboot4 su…

【MySQL】13. 索引(重点)

1. 没有索引&#xff0c;可能会有什么问题 索引&#xff1a;提高数据库的性能&#xff0c;索引是物美价廉的东西了。 不用加内存&#xff0c;不用改程序&#xff0c;不用调sql&#xff0c;只要执行正确的 create index &#xff0c;查询速度就可能提高成百上千倍。 但是天下没…

VMware ESXi部署macOS Monterey

正文共&#xff1a;1024 字 30 图&#xff0c;预估阅读时间&#xff1a;2 分钟 最早使用黑苹果是在2015年&#xff0c;装在了古老的Acer商务本上&#xff08;老樹發新芽&#xff0c;acer tm 4750g裝黑蘋果&#xff09;&#xff1b;上次安装黑苹果是在两年前&#xff08;VMware…