(13条消息) 有限状态机详解(转载)

以前总觉得有限状态机和无限状态机非常的难理解,原来也就是自己一直没有一个直观的认识,今天看到一篇博客,总算对有限状态机入门了。一看就懂。

转载地址:http://blog.csdn.net/zqixiao_09/article/details/50239337

我们知道,一般编写程序时都要画出流程图,按照流程图结构来编程,如果编写一个比较繁琐,容易思维混乱的程序时,我们可以利用有限状态机模型画出一个状态转移图,这样便可以利用画出的逻辑图来编写程序,简洁且不易出错。
那什么是有限状态机是什么意思呢?百度百科上这样解释:
有限状态机,(英语:Finite-state machine, FSM),又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。

常见的计算机就是使用有限状态机作为计算模型的:对于内存的不同状态,CPU通过读取内存值进行计算,更新内存中的状态。CPU还通过消息总线接受外部输入设备(如键盘、鼠标)的指令,计算后更改内存中的状态,计算结果输出到外部显示设备(如显示器),以及持久化存储在硬盘。
电脑游戏设计中也经常使用有限状态机模型。以水果忍者游戏为例,游戏中水果的状态是有限状态,其运行轨迹是由模拟物理运动规律的计算公式运算而成的,一个香蕉抛起来后会按照抛物线运行,其每一帧位置变化都是一个状态的改变,状态改变通过计算公式来决定。当然作为游戏不会仅仅这么简单,如果这么简单就是动画了,游戏还有复杂的人机交互事件,比如用手在屏幕上“切”了水果,水果感知到这个事件后,会按照程序逻辑进入爆炸状态。

简单知道其定义是没有用的,在C编程中我们改如何应用呢?

例题1:去除一个字符串中连续的空格,即 H__el___lo 变成 H_el_lo;

我们拿到这道题时,可能会想到用getchar()依次取字符,当遇到空格时,继续下一个字符是否为空格,如果是则删除,如果不是则继续;那么问题来了,如果空格后面还有空格呢?如果还有很多空格呢?如果还有其他要求呢?这样很容易造成思维混乱,所以这时我们可以用到有限状态机模型,好像这样说很模糊啊,该怎么使用呢?利用这种方式,最后的就是利用好flag,即标识符;这样吧,我们来画一下这个模型:

这样看好像有点抽象,我来解释一下:
状态0 (flag = 0)若当前字符是空格,输出并跳转到状态1(flag = 1),如果是非空格,则打印字符;
状态1 (flag = 1) 若当前字符为非空格,则输出并跳转到状态0,若是空格,则不打印;
下面几个例题我尽量写得清楚;

我们按照这种逻辑来写程序,看看是不是比较方便,代码如下:

#include <stdio.h>  

int main(int argc, char *argv[])
{
    char flag = 0;
    int ch;
    while((ch = getchar()) != EOF)
    {
        switch(flag)
        {
        case 0:
            if(ch == ' ')
                flag = 1;
            putchar(ch);
            break;
        case 1:
            if(ch == ' ')
                continue;
            flag = 0;
            putchar(ch);
            break;
        default:
            break;
        }
    }
    return 0;
}  

程序执行结果如下:

[cpp] view plain copy
fs@ubuntu:~/qiang/char1$ gcc -o test test.c
fs@ubuntu:~/qiang/char1$ ./test
H  el   lo
H el lo  

效果很明显;

上面的例题还算简单吧,好像不用这个模型也可以是吧,那好,我们再来一题

例题2:除连续的空格但字符串中的连续空格不变,比如H_ _el__"wor___ld"___lo;
大家看看,如果直接写程序是不是很烦,一会就乱掉了,那我们还用这个模型来编写,还是先画图:

#include <stdio.h>  

int main(int argc, char *argv[])
{
    char flag = 0;
    int ch;
    while((ch = getchar()) != EOF){
        switch(flag){
        case 0:
            if(ch == ' ')
                flag = 1;
            if(ch == '"')
                flag = 2;
            putchar(ch);
            break;
        case 1:
            if(ch != ' '){
                flag = 0;
                if(ch == '"')
                    flag = 2;
                putchar(ch);
            }
            break;
        case 2:
            if(ch == '"')
                flag = 0;
            if(ch == '\"')
                ch = '"';
            putchar(ch);
            break;
        default:
            printf("error!\n");
            break;
        }
    }
    return 0;
}  

执行结果如下:

[cpp] view plain copy
fs@ubuntu:~/qiang/char1$ ./char3
H  el  "wor   ld"   lo
H el "wor   ld" lo  

来个实际点的问题:
例题3::除单行注释
示例程序:

/*******this is program*****/
#include <stdio.h>
int main()
{
    printf("Hello world!\n");//Hello world!
}  

将这段程序中的单行注释去掉,继续画图:

编写程序如下:

#include <stdio.h>  

int main(void)
{
    char flag = 0;
    char ch;
    while((ch = getchar()) != EOF)
    {
        switch(flag)
        {
        case 0:
            if(ch == '/')
                flag = 1;
            else
                putchar(ch);
            break;
        case 1:
            if(ch == '/'){
                flag = 2;
            }
            else{
                putchar('/');
                putchar(ch);
            }
            break;
        case 2:
            if(ch == '\n')
            {
                flag = 0;
                putchar(ch);
            }
            break;
        default:
            break;
        }  

    }
}  

执行命令:

fs@ubuntu:~/qiang/char1$ ./quzhushi1 < test.c >result.c  

注意命令中用到的重定向,将test.c文件重定向到quzhushi1 中,输出结果重定向到 result.c中

可查看result.c中:

/*******this is program*****/
#include <stdio.h>
int main()
{
    printf("Hello world!\n");//Hello world!
}  

单行注释被删除。

例题4:去除单行注释和多行注释
还是这个测试程序:

/*******this is program*****/
#include <stdio.h>
int main()
{
    printf("Hello world!\n");//Hello world!
}  

好吧,继续画图,图上比较抽象,大家可以自己思考一下
这次比较复杂,要有5个标识符

测试代码如下:

#include <stdio.h>  

int main()
{
    char ch;
    int flag = 0;
    while((ch = getchar()) != EOF)
    {
        switch(flag)
        {
            case 0:
                if(ch == '/')
                    flag = 1;
                else
                    putchar(ch);
                break;  

            case 1:
                if(ch == '/')
                    flag = 2;
                else if(ch == '*')
                    flag = 3;
                else
                {
                    flag = 0;
                    putchar('/');
                    putchar(ch);
                }
                break;  

            case 2:
                if(ch == '\n')
                {
                    putchar(ch);
                    flag = 0;
                }
                break;  

            case 3:
                if(ch == '*')
                    flag = 4;
                break;  

            case 4:
                if(ch == '/')
                    flag = 0;
                else
                    flag = 3;
                break;
        }
    }
}  

执行命令:

fs@ubuntu:~/qiang/char1$ ./quzhushi < test.c >result.c  

执行结果:

/*******this is program*****/
#include <stdio.h>
int main()
{
    printf("Hello world!\n");//Hello world!
} 

大家可以比较画的图与所写程序,这种方法可以使我们编写程序时有个很好的思路!

(0)

相关推荐

  • 面试官让你用C语言实现大数相乘,慌吗?

    在之前的笔试题解析里面,我写了大数相加的问题,这里再剖析一个大数相乘,顾名思义,大数相乘就是这个数已经大到最大的数据类型都没有办法保存了. 我们看看最大的数据类型可以保存多大的数据. #include ...

  • C语言课程训练系统题-重庆邮电大学

    C语言课程训练系统题-基础习题 1.爱因斯坦 2.输出两数最大值 3.输出两数商 4.12a4.2 5判断3个数是否相等 6输入一个数,逆序输出这个数 7求三角形面积 8四则运算 9求2/1,3/2, ...

  • C语言fgetc和fputc函数用法详解(以字符形式读写文件)

    文章来源:http://c.biancheng.net/view/2068.html 在C语言中,读写文件比较灵活,既可以每次读写一个字符,也可以读写一个字符串,甚至是任意字节的数据(数据块).本节介 ...

  • (3条消息) busybox详解

    (3条消息) busybox详解

  • (1条消息) Pygame详解(十一):Rect 对象

    class pygame.Rect Rect 是用于存储矩形坐标的 Pygame 对象. Rect(left, top, width, height) -> Rect Rect((left, t ...

  • 高盐如何伤免疫?13.4分综述详解已知机制 | 热心肠日报

    今天是第1894期日报. 膳食钠摄入如何影响免疫系统(综述) Trends in Immunology[IF:13.422] ① 高盐饮食可刺激局部组织特异性的钠累积,如皮肤.胸腺.肝脾中Na+增加, ...

  • 早读|髌股关节骨关节炎诊疗指南(2020版),12条推荐意见详解!

    <中华医学信息导报>2020年18期第15版 膝关节骨关节炎是中老年人最常见的运动系统退行性疾病,根据病变部位不同分为单纯胫股关节骨关节炎(tibiofemoral osteoarthri ...

  • (13条消息) 机器学习

    时间序列分析预测法 简介 在之前,写了不少关于分类的算法,其中有传统机器学习算法如KNN.SVM,也有深度学习领域的算法如多层感知机,但是可以发现这里的算法核心思路都没有变化,利用一部分已有标签的数据 ...

  • (13条消息) DC

     1. 开关电源基础拓扑: BUCK减压型 先上电路图 图中器件T为  N-mos管 当PWM驱动高电平使得NMOS管T导通的时候,忽略MOS管的导通压降,等效如图2,电感电流呈线性上升,MOS导通时 ...

  • (13条消息) 音视频入门(四)

    一.JPEG的引入 JPEG属于一种图片压缩格式,之前我们通过对YUV420图像格式的学习,了解了怎么计算一帧YUV图像的大小.假设这里一帧图片的分辨率为1080p,像素格式为YUV420,那么它的大 ...

  • (13条消息) 工业相机的常见参数及选型

    一.相机成像原理如图所示: 注: 1)当物距为无穷远时,像距等于焦距,成像在焦平面上: 2)当物距为无穷无与两倍焦距之间时,像距在焦距与两倍焦距之间,成缩小的实像: 3)当物距等于两倍焦距时,像距与物 ...

  • (13条消息) 镜头的选型

    光学镜头在机器视觉系统中具有非常重要的地位,它的作用与人眼中的晶状体类似.一个光学镜头对像差校正的优良与否,即成像质量的好坏,可以通过像差的大小来衡量,一般较常见的像差类型有球差.像散.场曲.色差.畸 ...