状态机深入理解&简单代码实现

本文详细介绍了状态机的基础概念,包括其定义、分类,以及在程序控制流程中的关键作用。通过实例和设计思路展示了如何理解和使用状态机,并提供了一个简单的on/off开关代码实现。注意区分状态与动作,遵循状态完整性原则。

什么是状态机?

状态机在我们的程序设计中非常重要,查阅了一些资料写了这篇文章来梳理和复习。

状态机的定义

关于状态机的一个极度确切的描述是:它是一个有向图形,由一组节点和一组相应的转移函数组成。状态机通过响应一系列事件而“运行”
是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。

每个事件都在属于“当前”
节点的转移函数的控制范围内,其中函数的范围是节点的一个子集。函数返回“下一个”(也许是同一个)节点。这些节点中至少有一个必须是终态。当到达终态,
状态机停止。 包含一组状态集(states)、一个起始状态(start
state)、一组输入符号集(alphabet)、一个映射输入符号和当前状态到下一状态的转换函数(transition
function)的计算模型。当输入符号串,模型随即进入起始状态。它要改变到新的状态,依赖于转换函数。

官方定义 不理解可以往下看。

状态机的分类

状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调相关信号动作、完成特定操作的控制中心。有限状态机简写为FSM(Finite State Machine),主要分为2大类:
第一类,若输出只和状态有关而与输入无关,则称为Moore状态机
第二类,输出不仅和状态有关而且和输入有关系,则称为Mealy状态机

状态机的应用

程序中有两大类:一类是传统应用程序的控制流程基本是顺序的,主要指控制台程序等“命令行实用程序”。
一类应用程序由外部发生的事件来驱动 ,事件驱动的GUI应用程序是这种应用程序的典型例子,它们由命令和选择(也就是用户造成的事件)来驱动。Web应用程序由提交的表单和用户请求的网页来驱动,它们也可划归到上述类别。

状态机理解&实例

状态机可归纳为4个要素,即现态、条件、动作、次态。这样的归纳,主要是出于对状态机的内在因果关系的考虑。“现态”和“条件”是因,“动作”和“次态”是果。详解如下:
①现态:是指当前所处的状态。
②条件:又称为“事件”,当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。
③动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
④次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。

状态机就是状态转移图。最简单的例子,人有三个状态:健康,感冒,康复中。触发的条件有淋雨(t1),吃药(t2),打针(t3),休息(t4)。所以状态机就是健康-(t4)->健康;健康-(t1)->感冒;感冒-(t3)->健康;感冒-(t2)->康复中;康复中-(t4)->健康,等等。就是这样状态在不同的条件下跳转到自己或不同状态的图。

设计思路

做需求时,需要了解以下六种元素:起始、终止、现态、次态(目标状态)、动作、条件,我们就可以完成一个状态机图的设计了。起始和终止是特殊的现态和次态
在实际开发中需要用画图工具画出状态机图后再开发
在这里插入图片描述

注意事项

1、避免把某个“程序动作”当作是一种“状态”来处理。那么如何区分“动作”和“状态”?“动作”是不稳定的,即使没有条件的触发,“动作”一旦执行完毕就结束了;而“状态”是相对稳定的,如果没有外部条件的触发,一个状态会一直持续下去。

2、状态划分时,必须保证状态的完整性。

代码实现

现在状态机有很多好用的类库,这里推荐github的https://github.com/dotnet-state-machine/stateless state machine

实现最简单的on/off

using System;
using Stateless;

namespace OnOffExample
{
    /// <summary>
    /// This example has a simple state machine with only two states. The state
    /// information is of type string, and the type of the trigger is char. 
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            const string on = "On";
            const string off = "Off";
            const char space = ' ';

            // Instantiate a new state machine in the 'off' state
            var onOffSwitch = new StateMachine<string, char>(off);

            // Configure state machine with the Configure method, supplying the state to be configured as a parameter
            onOffSwitch.Configure(off).Permit(space, on);
            onOffSwitch.Configure(on).Permit(space, off);

            Console.WriteLine("Press <space> to toggle the switch. Any other key will exit the program.");

            while (true)
            {
                Console.WriteLine("Switch is in state: " + onOffSwitch.State);
                var pressed = Console.ReadKey(true).KeyChar;
                
                // Check if user wants to exit
                if (pressed != space) break;

                // Use the Fire method with the trigger as payload to supply the state machine with an event.
                // The state machine will react according to its configuration.
                onOffSwitch.Fire(pressed);
            }
        }
    }
}

### 如何在DFA状态转换图中确定终止状态 在NFA到DFA的转换过程中,终止状态的确定是至关重要的一步。为了确保DFA能够正确地接受或拒绝字符串,需要追溯到NFA中定义的终止状态,并考虑状态迁移时可能达到的所有路径[^1]。 在子集构造算法中,每个DFA的状态实际上对应于NFA中的一个状态集合。因此,DFA中的终止状态是由NFA中的终止状态决定的。具体来说,如果某个DFA状态(即NFA状态的集合)包含至少一个NFA的终止状态,则该DFA状态被标记为终止状态。例如,在一个具体的例子中,如果某个DFA状态 \( D \) 包含了NFA的终止状态集合中的元素(如状态 9),那么 \( D \) 就会被视为DFA的终止状态[^2]。 此外,子集构造算法的核心思想是将NFA的状态集合化,从而消除不确定性,使得每个输入字符都能唯一地决定下一个状态。由于NFA的状态转移可能存在多条路径,因此通过计算 &epsilon;-closure(空闭包)来涵盖所有可能的状态迁移[^3]。最终,当某个状态集合与NFA的终止状态集合有交集时,这个状态集合就被认为是DFA的终止状态。 在实际实现中,可以通过以下代码片段模拟DFA的状态转换,并判断是否到达终止状态: ```python # 假设我们有一个DFA的状态转换表 Map 和终止状态集合 final_states def is_accepted(Map, final_states, s_begin, str, alpha2idx): curState = s_begin # 初始状态 for char in str: if char not in alpha2idx: # 如果字符不在字母表中 return False nextState = Map[curState][alpha2idx[char]] if nextState == -1: # 如果没有对应的转换关系 return False curState = nextState # 更新当前状态 return curState in final_states # 判断最后是否达到了结束状态 # 示例使用 Map = { 0: {&#39;a&#39;: 1, &#39;b&#39;: -1}, 1: {&#39;a&#39;: -1, &#39;b&#39;: 2}, 2: {&#39;a&#39;: -1, &#39;b&#39;: -1} } final_states = {2} # 终止状态集合 s_begin = 0 # 初始状态 alpha2idx = {&#39;a&#39;: 0, &#39;b&#39;: 1} print(is_accepted(Map, final_states, s_begin, &quot;ab&quot;, alpha2idx)) # 输出 True ``` 上述代码展示了如何根据输入字符串和状态转换表判断是否到达DFA的终止状态。如果最终状态属于终止状态集合,则返回 `True`,否则返回 `False`[^4]。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值