有限状态机

news2025/1/16 1:36:06

文章目录

  • 1.概念
  • 2.什么是计算
  • 3.什么是有限状态机
    • 3.1特性
    • 3.2为什么要用状态机
  • 4.实战
    • 4.1字符串转换整数
    • 4.2用有限状态机实现
    • 4.3源码

1.概念

有限状态机(英语:finite-state machine,缩写:FSM)又称有限状态自动机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学计算模型。(来自维基百科)

2.什么是计算

在讲有限状态机之前,我们先了解一下什么是计算。计算,简单来说就是有一个问题,然后给出答案。比如知道边长,求正方形的面积;又比如知道两个点和已知路径,求最短路径等等,有无穷无尽的问题。

如果用计算机的模型去处理这些问题的话,我们希望是统一的。那么怎么将问题统一化呢?

把所有问题都变成判定问题,即是和否

image-20230108230150973

3.什么是有限状态机

有限状态机,顾名思义,就是在有限个状态之间流转,即FSM的下一个状态和输出是由输入和当前状态决定的。

3.1特性

有限状态机(Finite-state machine)有三个特征:

  1. 状态总数(state)是有限的。
  2. 任一时刻,只处在一种状态之中。
  3. 某种条件下,会从一种状态转变(transition)到另一种状态。

3.2为什么要用状态机

其实我们在编程时实现相关业务逻辑时经常需要处理各种事件和状态切换,写各种switch/case 和if/else ,所以我们其实可能一直都在跟有限状态机打交道,只是可能没有意识到。现在假如有个订单系统,目前订单上的状态由待支付、已支付、已退款3个状态,这个时候我们可以简单地通过switch/case 和if/else进行实现,但是实际的一个成熟的订单系统是极其复杂的,包括但不限于

  1. 订单状态多
  2. 一个订单包含很多个子订单
  3. 订单流转的操作很多都是公共的
  4. 随着业务发展,也会时不时地多出几个状态等等,

那么这个时候再用if/else实现,就会导致代码耦合严重、分支多、重复代码多等问题,而且随着状态的增加,对原有代码逻辑的修改就会变的非常困难,这个时候就需要有限状态机来处理了。

所以在处理一些业务逻辑比较复杂的需求时,可以先看看是否适合用一个有限状态机来描述,如果可以把业务模型抽象成一个有限状态机,那么代码就会逻辑特别清晰,结构特别规整。

4.实战

4.1字符串转换整数

这是力扣的一道题,题目描述:

请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。

函数 myAtoi(string s) 的算法如下:

  1. 读入字符串并丢弃无用的前导空格
  2. 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
  3. 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
  4. 将前面步骤读入的这些数字转换为整数(即,“123” -> 123, “0032” -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
  5. 如果整数数超过 32 位有符号整数范围 [−231, 231 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −231 ,大于 231 − 1 的整数应该被固定为 231 − 1

4.2用有限状态机实现

有限状态机就是通过一个个的输入作为触发器,将当前状态流转到下个状态。针对该题,可以用有限状态机表示

我们的程序在每个时刻有一个状态 s,每次从序列中输入一个字符 c,并根据字符 c 转移到下一个状态 s’。这样,我们只需要建立一个覆盖所有情况的从 s 与 c 映射到 s’ 的表格即可解决题目中的问题。

image-20230108225112307

用表格表示是这样的

’ ’+/-numberother
startstartsignedin_numberend
signedendendin_numberend
in_numberendendin_numberend
endendendendend

4.3源码

class Solution {
    public int myAtoi(String s) {
        Automaton automaton = new Automaton();
        for (int i=0; i<s.length(); i++) {
            automaton.get(s.charAt(i));
            if (automaton.isEnd) {
                return automaton.ans * automaton.sign;
            }
        }
        return automaton.ans * automaton.sign;
    }
  

    public static class Automaton {

        public Boolean isEnd = false;

        public int ans = 0;

        public String state = "start";

        public int sign = 1;


        public Map<String, String[]> table = new HashMap<String, String[]>() {{
            put("start", new String[]{"start", "signed", "in_number", "end"});
            put("signed", new String[]{"end", "end", "in_number", "end"});
            put("in_number", new String[]{"end", "end", "in_number", "end"});
            put("end", new String[]{"end", "end", "end", "end"});
        }};


      //该方法即为字符输入的触发
        public void get(char c) {
            state = table.get(state)[getCol(c)];
            if("end".equals(state)) {
                isEnd = true;
            } else if ("signed".equals(state)) {
                sign = c == '+'? 1 : -1;
            } else if ("in_number".equals(state)) {
                if (sign > 0) {
//                    ans = ans * 10 + c - '0';
                    if (ans > Integer.MAX_VALUE/10 || (ans == Integer.MAX_VALUE/10 && c - '0' > Integer.MAX_VALUE%10)) {
                        ans = Integer.MAX_VALUE;
                        isEnd = true;
                        return;
                    }
                } else {
                    if (-ans < Integer.MIN_VALUE/10 || (-ans == Integer.MIN_VALUE/10 && '0' - c < Integer.MIN_VALUE%10)) {
                        ans = Integer.MIN_VALUE;
                        isEnd = true;
                        return;
                    }
                }
                ans = ans * 10 + c - '0';
            }
        }


        public int getCol(char c) {
            if (c == ' ') {
                return 0;
            }
            if (c == '+' || c == '-') {
                return 1;
            }
            if (Character.isDigit(c)) {
                return 2;
            }
            return 3;
        }
    }
}

https://blog.lerzen.com/post/%E6%9C%89%E9%99%90%E7%8A%B6%E6%80%81%E6%9C%BAfsm%E7%9A%84%E7%AE%80%E4%BB%8B%E4%B8%8Edemo/

https://zhuanlan.zhihu.com/p/46347732

https://www.bilibili.com/video/BV1Yi4y1t7J3?p=2&spm_id_from=pageDriver&vd_source=e2283db23f05299cbaebf6984607a0e6

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

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

相关文章

【手写 Vue2.x 源码】第十篇 - 数组数据变化的观测情况

一&#xff0c;前言 上篇&#xff0c;主要介绍了对象数据变化的观测情况&#xff0c;涉及以下几个点&#xff1a; 实现了对象老属性值变更为对象、数组时的深层观测处理&#xff1b; 结合实现原理&#xff0c;说明了对象新增属性不能被观测的原因&#xff0c;及如何实现数据…

综合案例二 旅游网【1.项目导入技术选型注册表单校验登录退出表单】注册表空指针异常和其他一些错误

目录 前提&#xff1a;项目导入 在maven中点击travel项目&#xff08;这里我是将项目添加到hello_maven里 &#xff09; 1.启动项目 方式一&#xff1a;maven命令启动 方式二&#xff1a;配置maven快捷启动 2.技术选型 1 Web层 2 Service层 3 Dao层 3.创建数据库…

56/14 shell脚本 后台启动 程序1 + “tail -f log“, ctrl +c 导致程序1中断

前言 接上一篇文章, node 程序后台执行加上 tail 命令, 中断 tail 命令, 同时也中断了 node 程序 我们来详细 参照对比一下 这个问题的各种情况 主要的脚本如下类似, 第一条命令 后台启动 程序1, 然后 第二条命令 tail -f 查看日志 然后 ctrlc 中断 "tail -f" …

实现自己的打印函数

文章目录前言前置知识代码说明实验操作单字符打印字符串打印整形字符串打印前言 本博客记录《操作系统真象还原》第六章实验的操作~ 实验环境&#xff1a;ubuntu18.04VMware &#xff0c; Bochs下载安装 实验内容&#xff1a; 实现 put_char 单字符打印输出函数。实现 put_…

TEE 背景知识

TEE 背景 计算机世界的安全&#xff0c;是保护计算机系统和网络免受攻击者的攻击&#xff0c;这些攻击可能导致未经授权的信息泄露、窃取或损坏硬件、软件或数据&#xff0c;以及它们所提供的服务的中断或误导。更多参考 Computer_security 1 安全是什么 谈安全&#xff0c;…

28.0:Combit LIST LABEL Reporting for Delphi Crack

作为 Delphi 开发人员的优势&#xff1a; 将 VCL 组件直接集成到 Embarcadero IDE 中 免版税报表设计器 交互式预览等 使用综合报表对象 Delphi 和所有其他相关语言和开发环境的报告工具。 将列表和标签集成到 Embarcadero RAD Studio List & Label 的 VCL 组件编译并直接…

HTML与CSS基础(八)—— CSS布局(定位、装饰、选择器拓展)

目标能够说出 定位 的常见应用场景 能够说出 不同定位方式 的特点 能够使用 子绝父相 完成元素水平垂直案例 能够写出三种常见的 光标类型&#xff08;cursor&#xff09; 能够使用 圆角边框 属性完成 正圆 和 胶囊按钮 效果 能够说出 display 和 visibility 让 元素本身隐藏 的…

【java查漏补缺】File类的使用

File类可以用来处理文件数据&#xff0c;比如使用list()方法可以获得某个文件夹下面的所有文件名。 File类的list()方法有一个含有一个参数的重载&#xff0c;在调用该方法的时候需要传入一个FilenameFilter对象&#xff0c;这样便可以进行文件名过滤。 我们先来看一下list()…

GJB 5000B二级-PP项目策划

一、主要变化情况 合并10项(绿色)、修订3项(蓝色)、删除1项(红色) 新增的主要内容 基于A版标准“项目策划”、“集成项目管理”、“定量项目管理”三个过程域中有关项目策划实践的内容来识别,没有新增实践,只增加了以下两个要求: 1、增加软件项目和设备/系统生存周…

Java线程之中断方法

interrupt()方法介绍interrupt() 给目标线程发送一个中断信号&#xff0c;同时将目标线程的中断标志设置为true。至于目标线程是否做出响应&#xff0c;需要看目标线程是否有对应的中断业务逻辑。场景1&#xff1a;假设&#xff0c;你是一个工厂的老板&#xff08;main线程&…

C++类和对象(下)

目录 初始化列表 explicit关键字 Static成员 友元 友元函数 友元类 匿名对象 内部类 初始化列表 初始化列表是以冒号开始&#xff0c;以逗号分割的成员列表&#xff0c;每一个成员变量后面跟一个放在括号中的初始值或表达式。&#xff08;代码演示以日期类为例&#xff…

【实现QQ登录界面 Objective-C语言】

一、实现QQ登录界面 1.实现这样的QQ登录界面 1.实现这样的QQ登录界面 2.首先,分析一下,这个界面里,都有哪些控件 是不是两个Label,两个TextField文本框,1个Button吧 3.先拖1个Label上来 再拖1个TextField文本框上来,在这个Label右边, 然后选中这两个控件, 按住o…

Altium Designer 超详细学习教程——印制电路板基础知识

在介绍Altium Designer软件使用办法之前先介绍下印制电路板的基础知识&#xff0c;不管是画图还是绘制PCB最终目的都是为了制作电路板&#xff0c;因此了解PCB的基础知识很有必要。 1.1印制电路板概述 1.1.1印制电路板结构 在进行PCB设计时&#xff0c;需要先对印制电路板的…

【Linux】对于make/Makefile的使用

本文目录 背景简介 细说关于make命令和makefile文件&#xff1a; 使用方法 为什么执行的指令是make和make clean呢&#xff1f; gcc如何判断文件是否需要重新执行&#xff1f; 背景简介 一个工程中的源文件不计数&#xff0c;其按类型、功能、模块分别放在若干个目录中&…

064-Tcp/IP通讯使用ServerSocket及Server实现多人在线聊天项目实训

【上一讲】063-Tcp/IP通讯使用ServerSocket及Server实现多人在线聊天_CSDN专家-赖老师(软件之家)的博客-CSDN博客 本文主要讲解使用ServerSocket,Socket类实现多人同时在线聊天的网络通讯程序,主要功能及技术如下: 1.使用ServerSocket,Socket类实现网络通讯功能; 2.使用…

【go语言之websocket】

go语言之websocket写在前面服务端msggetConnUpgradeNewWsConnectionNextWriterwriteread客户端抓包表现总结写在前面 之前的文章都是介绍的是http的使用&#xff0c;这里主要介绍的是websocket,主要是解决长连接场景下的使用。这里概念不多说&#xff0c;网上很多&#xff0c;…

Ajax篇-前后端交互, 接口文档, ajax, axios, fetch,Postman工具

前后端交互接口文档请求方法区分方式GETPOST从语义上区分偏向于查询&#xff08;获取数据....&#xff09;偏向于提交数据(注册,修改,删除...)安全性显示的携带参数,参数是直接拼接在请求地址之后,安全性较差,隐私性差隐式的携带参数,不会在请求地址上显示,安全性好,以JSON格式…

网络虚拟化基本架构

文章目录架构概述架构图核心组件OpenFlow SwitchPipelineFlow Table EntryInstructionOpenFlow Switch Protocol测试验证Pipeline流表项间流程流表间流程Flow Table EntryInstructionsSwitch ProtocolFaucet架构概述 我们知道网络虚拟化的主要目标就是让报文可以在虚拟机之间进…

Windows Anaconda YOLOv3环境部署--2023年1月8日

时效性&#xff1a; 2023年1月8日 目录摘要1 使用 Anaconda 创建虚拟环境2 安装官方要求的依赖库3 验证安装 | 执行 detect.py 示例代码Key already registered with the same priority摘要 网好的可以直接参考官方文档安装&#xff0c;遇到安装报错和网络问题可以参考本文 本地…

网络安全等级保护定级指南 范围

声明 本文是学习github5.com 网站的报告而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 网络安全等级保护 为了配合《中华人民共和国网络安全法》的实施&#xff0c;适应云计算、移动互联、物联网、工业控制和大数据等新技术、新应用情况下网络安全等…