状态机及其应用

  • Post author:
  • Post category:其他





前言


我们在看编程资料或者程序设计文档时,经常碰见的一个词就是状态机,状态机是什么?包含什么基本概念?在日常工作中,我们如何应用状态机模型解决实际编程问题?本文将一一进行解答,并给出一个使用状态机解析单词个数的C语言例子,该例子的目的是从输入流中解析出英文单词的个数。





一、什么是状态机


状态机一般指的是有限状态机(Finite-state machine, FSM),又称有限状态自动机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。它是一种用来进行对象行为建模的工具,通常使用状态表或状态图来表示。相比于程序流程图和时序图,状态图表现更加直观,非常通俗易懂,即使是非编程技术人员,也能一目了然。




二、状态机的四个基本要素



1.现态


指状态机当前所处的状态。



2.条件


条件,又称“事件”,当一个条件被满足,将会触发一个动作或执行一次状态迁移。



3.动作


条件满足后执行的动作。动作执行完后,状态可以迁移到下一个状态,也可以继续保持当前状态。动作并不是必须的,当条件满足时,可以不执行动作,状态也可以迁移到下一个状态。



4.次态


当条件满足后,迁移到的新状态。当状态迁移到新状态后,新状态即变成现态。“次态”是相对于“现态”而言的。




三、使用状态机解决单词解析问题

题目:给定一个字符流,使用状态机技术解析其中包含的单词个数,划分单词的分隔符只考虑【逗号】【句号】【空格】,实现获取单词个数接口:int32_t get_word_count(const char* input)。



1.状态定义


(1)Init:单词解析工作的初始化状态。

(2)In_word:当前处理的字符不属于分隔符,则进入单词状态,表示当前处于一个单词当中。

(3)Out_word:当前处理的字符属于分隔符,则进入非单词状态,表示在单词之外.

(4)Final:当处理达到字符流结束,则进入结束状态,表示单词解析工作结束。




2.条件定义


1、NOT_SEPARATION:当读取到的字符不是分隔符,如果当前状态是【In_word】将保持在【In_word】;如果当前状态是【Init】或【Out_word】则进入【In_word】状态。

2、SEPARATION:当读取到分隔字符时,如果当前状态是【Out_word】,将保持在【Out_word】;如果当前状态是【Init】或【In_word】则进入【Out_word】状态。 3、STOP:当到达字符流结束位置时,进入状态【Final】,解析工作结束。



3.动作定义


1、状态从【Init】转移到【In_word】,单词个数加一;

2、状态从【Out_word】转移到【In_word】,单词个数加一;

3、状态转移到【Final】,返回单词个数,解析工作结束。



4.状态机图


下面是自己画的一张极丑的状态图,状态图中没有画从Init 到Final的线。

在这里插入图片描述



5.C语言实现源码


typedef enum _state_t {
	INIT,
	IN_WORD,
	OUT_WORD,
	FINAL
}state_t;

typedef enum _event_t {
	SEPARATION = 1,
	NOT_SEPARATION,
	STOP
}event_t;

//动作前输入单词统计个数,动作后返回处理后的单词个数
typedef int32_t (*action_t)(int32_t word_count);

typedef struct _state_transformation_t {
	state_t current_state;  //当前状态,现态
	event_t current_event;  //当前发生的事件,条件
	state_t next_state;     //下个状态,次态
	action_t action;        //状态迁移时发生的动作
}state_transformation_t;

typedef struct _state_machine_t {
	state_t state;                                 //当前状态
	int32_t transformation_count;                  //状态迁移的个数
	state_transformation_t* transformation_array;  //状态迁移的列表
}state_machine_t;

static  state_transformation_t* find_transformation(const state_machine_t* state_machine, const event_t event) {
	if (state_machine == NULL) {
		return NULL;
	}

	for (int i = 0; i < state_machine->transformation_count; i++) {
		if (state_machine->state == state_machine->transformation_array[i].current_state && event == state_machine->transformation_array[i].current_event) {
			return &state_machine->transformation_array[i];
		}
	}

	return NULL;
}

static int32_t count_add_one(int32_t currrent_word_count) {
	return currrent_word_count + 1;
}

int32_t count_not_change(int32_t currrent_word_count) {
	return currrent_word_count;
}

static event_t current_event(const char* one_char) {
	char separate_char[] = { ',', '.', ' ' };
	char final_char = '\0';

	if (one_char == final_char) {
		return STOP;
	}

	for (int i = 0; i < sizeof(separate_char); i++) {
		if (one_char[0] == separate_char[i]) {
			return SEPARATION;
		}
	}

	return NOT_SEPARATION;
}

static int32_t get_word_count_ext(state_machine_t* state_machine, const char* words) {
	int32_t word_count = 0;
	char* one_char = words;

	while (strlen(one_char) != 0)
	{
		state_transformation_t* state_transformation = find_transformation(state_machine, current_event(one_char));
		if (state_transformation == NULL) {
			return 0;
		}

		state_machine->state = state_transformation->next_state;
		action_t action = state_transformation->action;
		if (action != NULL) {
			word_count = action(word_count);
		}

		one_char = one_char++;
	}
	
	return word_count;
}
int32_t get_word_count(const char* input) {
	state_transformation_t state_transformation_array[] = {
		{INIT, NOT_SEPARATION, IN_WORD, count_add_one},
		{INIT, SEPARATION, OUT_WORD, count_not_change},
		{INIT, STOP, FINAL, count_not_change},
		{IN_WORD, STOP, FINAL, count_not_change},
		{IN_WORD, NOT_SEPARATION, IN_WORD, count_not_change},
		{IN_WORD, SEPARATION, OUT_WORD, count_not_change},
		{OUT_WORD, SEPARATION, OUT_WORD, count_not_change},
		{OUT_WORD, NOT_SEPARATION, IN_WORD, count_add_one},
		{OUT_WORD, STOP, FINAL, count_not_change},
	};

	//初始化状态机
	state_machine_t word_statistic_state_machine;
	word_statistic_state_machine.state = INIT;
	word_statistic_state_machine.transformation_count = sizeof(state_transformation_array) / sizeof(state_transformation_t);
	word_statistic_state_machine.transformation_array = state_transformation_array;

	return get_word_count_ext(&word_statistic_state_machine, input);
}

int main(int argc, char* argv[]) {
	//26 words
	char* input = "There are moments in life, when you miss someolifene so much that you just want to pick them from your dreams and hug them for real.";
	//char* input2 = "hello, hi.";
	int32_t word_count = get_word_count(input);
	printf("words count:%d\n", word_count);
}

运行输出:

在这里插入图片描述



总结


以上就是今天要讲的内容,本文仅仅简单介绍了状态机,以及使用C语言实现状态机解析单词个数的功能。希望这些内容能对每一个读者有所帮助,有不足的地方,还请留言指正,不甚感激!!!



版权声明:本文为woody218原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。