【问题标题】:Is it possible to traverse a binary tree with a finite-state machine?是否可以使用有限状态机遍历二叉树?
【发布时间】:2016-08-19 03:19:13
【问题描述】:

早安,

要明确一点:我不是在寻找递归或迭代解决方案,维基百科有足够的伪代码来实现任何树的前序、中序和后序遍历。

我有兴趣构建一个有限状态机来遍历二叉树。

一棵树由节点组成。节点具有 LeftChild、RightChild 和 Parent 属性。

FSM 在任何给定时间停在一个节点上,并且可以根据需要具有任意多的状态,但没有任何类型的动态堆栈(这将它与图灵机区分开来)。在输入“GiveNext”时,机器应该在下一个节点上停止(比如遍历树的前序。)

我已经尝试了很长时间,并且怀疑这是不可能的,但我不确定。问题是需要跟踪最近的决定,以便在通过父节点重新访问节点时,在处理完左侧节点后可以右转。

想法?

提前致谢! 药草

【问题讨论】:

  • 你看过莫里斯中序遍历吗? en.wikipedia.org/wiki/…
  • 谢谢你,@msandiford。当按顺序访问树时,使用线程二叉树 (link) 会很好。不幸的是,改变树的布局是不可能的。由于树是前缀树(又名 Patricia trie),因此最明智的访问方式是预购。出于好奇(因为无论如何我都无法更改树布局):没有用于前序遍历的线程二叉树,还是有?

标签: tree-traversal state-machine


【解决方案1】:

这种练习可能有很多限制,我可能会错过。我希望这至少有点用处。

我假设 FSM 在任何给定时间“站立”在“当前节点”上是可以接受的,因此它有可用的输入返回正确的 0/1 值以及有关此当前节点的信息。

输入:

  • AmIALeftChild(如果当前节点挂在其父节点的左侧,则为 1,否则为 0)
  • AmIARightChild(如果我挂在父节点的左侧,则为 1,否则为 0)
  • 有左孩子吗? (如果我有一个左孩子,则为 1,否则为 0)
  • 有正确的孩子吗? (如果我有一个正确的孩子,则为 1,否则为 0)

按照这 3 个输出中的说明“遍历”是否可以?

输出:

  • GoToLeftChild
  • GoToRightChild
  • 集团

(在任何给定时间,3 个输出中只有 1 个可以为真)

如果两个约束都允许,那么您可以构建一个像这样的 FSM:

国家

  • 启动
  • NormalTraverse
  • 从左返回
  • GoBackFromRight
  • 完成

这是状态机:

开始 -> 只是进入 NormalTraverse 状态(假设我们在根上,对) 正常遍历 -> 如果 HaveLeftChild=1 那么 设置 GoToLeftChild=1(其他输出为 0) 转到正常遍历 否则,如果有对的孩子,那么 设置 GoToRightChild=1 转到正常遍历 ElseIf AmIALLeftChild Then 设置 GoUp=1 GoBackFromLeft ElseIf AmIARightChild Then 设置 GoUp=1 GoBackFromRight 别的 转到完成。 从左返回 -> If HaveRightChild Then 设置 GoToRightChild=1 转到正常遍历。 ElseIf AmIALLeftChild Then 设置 GoUp=1 GoBackFromLeft ElseIf AmIARightChild Then 设置 GoUp=1 GoBackFromRight 别的 转到完成。 从右返回 If AmIALLeftChild Then 设置 GoUp=1 GoBackFromLeft ElseIf AmIARightChild Then 设置 GoUp=1 GoBackFromRight 别的 转到完成。

请原谅我的英语,请注意代码不是程序性的,并且在正确地“按位”“扩展”它们之后,“IF”应该是互斥的。但我以这种方式写它是为了节省一点时间。如果您不明白我的意思,请询问。

【讨论】:

  • 谢谢杰拉尔多。事实上,当我看到你的工作时,我同时在一个类似的解决方案上工作并回来发布它。感谢您的宝贵时间!
【解决方案2】:

这是我经过多张纸值半棵树后想出的,主要是画很多二叉树(尤其是退化的)来验证FSM是否正常工作。

唯一需要始终访问的变量是起始节点。这可以是树中的任何节点:FSM 只遍历这个子树。

假设开始节点已经被处理(或不需要处理)。但是,如果您的应用程序不是这种情况,那么集成起来很容易:在 GO LEFT 步骤之前,只需为起始节点添加一个测试:I AM START。如果为 TRUE,则报告,否则如图所示继续。

单个动作意味着:

  • GO LEFT - 使当前节点的左子节点成为当前节点,如果有的话。如果成功,则答案是 OK,如果没有这样的节点,则答案是 No Left。
  • GO RIGHT - 使当前节点的右孩子成为当前节点,如果有的话。如果成功,答案是 OK,如果没有这样的节点,答案是 No Right。
  • GO UP - 使当前节点的父节点成为当前节点。结果只有一种状态。对于根,父不存在,但 FSM 永远不会尝试访问根的父。
  • I AM LEFT - 测试当前节点是否是其父左子节点。答案是对还是错。
  • I AM RIGHT - 测试当前节点是否是其父右孩子。答案是对还是错。
  • I AM START - 测试当前节点是否为起始节点。答案是对还是错。

【讨论】:

  • 您的图表对输入/条件评估和状态使用相同的符号。这有点令人困惑,如果你改变它看起来像我的答案......看起来它工作正常
  • 那么状态机的状态是什么?向左/向右/向上是输出。我是左/右/开始是输入。哪些是州?即使有解释,您仍然在绘制流程图,而不是状态机。
  • 对不起,太出风头了。如果这是家庭作业,那就是老师会要求的。
  • 没有问题,Gerardo,事实上,我很感激。状态是两个框框: 报告(如:实际节点是当前访问的节点,它已准备好以任何方式被消费);和 EndOfTree(如:遍历起始节点指定的子树的所有节点)。
  • 哦,我刚刚意识到有框的盒子。但它仍然看起来不是 100% 好的。鉴于 FSM 不是程序性的,并且给定一个状态,您可以读取输入、设置输出并移动到其他状态:您不满足该规则,因为在某些情况下您正在做出两个链式决策,例如“两个不同的sequential 输出”,在开始状态和下一个状态之间。那不应该被允许。 (您缺少中间状态)。例如:如果我在树的低处:报告->不能向左走,不能向右走,所以,我向上移动,因为现在我不是根,我向右走...:两个移动 wo/状态改变:(
猜你喜欢
  • 1970-01-01
  • 2014-04-30
  • 2012-01-01
  • 2022-11-11
  • 1970-01-01
  • 2021-11-20
  • 2017-08-23
相关资源
最近更新 更多