【问题标题】:Understanding Wikipedia code for a generic depth-first tree search?了解通用深度优先树搜索的维基百科代码?
【发布时间】:2012-02-13 07:05:05
【问题描述】:

我正在复习不同的树遍历方法并最终阅读了以下*article。正如所料,二叉树的深度优先遍历有三种方法:

  1. 前序遍历
  2. 后序遍历
  3. 中序遍历

然后本文继续处理任意(通用)树的深度优先遍历。为方便起见,我将其粘贴在这里:

// To traverse a non-empty tree in depth-first order,
// perform the following operations recursively at each node:
Perform pre-order operation
for i=1 to n-1 do
    Visit child[i], if present
    Perform in-order operation

Visit child[n], if present
Perform post-order operation

这是*提供的所有解释:

其中 n 是子节点的数量。根据问题 手,预购,中购或后购操作可能无效,或 你可能只想访问特定的子节点,所以这些操作 应该被认为是可选的。此外,在实践中不止一种 可能需要进行预购、中购和后购操作。为了 例如,当插入三叉树时,预排序操作是 通过比较项目来执行。可能需要进行后订购操作 之后重新平衡树。

指定的算法对我来说毫无意义,因为它是根据未定义的操作指定的:

  1. 预购操作。
  2. 后订购操作。
  3. 顺序操作。

为了增加混乱,我无法根据我所知道的和*文章中的内容来定义上述操作。我一直对此感到困惑,但没有真正的突破。我有以下问题:

  1. *文章中指定的算法是否错误?我怀疑是这样,但除了指定不明确的事实之外,不能肯定地说任何话。
  2. 是否为通用树定义了后序、前序、中序深度优先遍历?这些实用吗?是否与三个操作的定义有关?如果是这样,怎么做?
  3. 如果算法确实是正确的,有人可以为我定义上述操作并解释它是如何工作的吗?

【问题讨论】:

  • 你的意思是,你不知道什么是inorder/preorder/post order操作?
  • @Poonam,我不知道这些操作在算法上下文中意味着什么。通常,我会将其视为在一个“父”节点及其所有子节点上工作的相应遍历(前序/后序/中序)的一个步骤。
  • @Poonam,我已经阅读了*的文章和一堆其他定义这些东西的东西。只是为了确保,我也通读了你的 PDF。我很清楚后序/预序/中序遍历是如何工作的,如何使用堆栈递归/迭代地对它们进行编码。我特别挂断的是在这种情况下对这些操作的定义以及如何同时完成这三个操作。 templatetypedef 的回答清除了大部分内容,但我仍然对如何定义单个此类操作感到困惑。
  • @Poonam,我之前的评论没有冒犯的意思。我只是在澄清我的问题。我将不胜感激单个 preorder/postorder/inorder 操作的良好定义。对于通用树,考虑一个节点 A,其子节点为 a1、a2、...、an。前序操作是否定义为按照 A、a1、a2、...、an 的顺序访问?我想变得非常具体,并且 100% 确定。
  • 按顺序遍历左节点,如果左节点为空,则打印节点数据,然后打印数据的右侧再次从左侧开始工作,null找到打印数据,然后右节点和过程重复,在前序中,首先打印数据,然后到左树打印数据,然后向左打印数据,直到找到空值,然后向右并重复处理,对于后序,首先遍历左到空,然后从最后一个左节点的右侧遍历并重复处理,最后将打印数据,如果不让我知道,我假设您知道这些差异,我会举例说明

标签: algorithm data-structures tree depth-first-search tree-traversal


【解决方案1】:

所述的算法确实是正确的。在这种情况下发生的情况是,Wikipedia 文章包含一段代码,该代码处理一个处理前序、中序和后序遍历的一般情况。

您可以将前序、中序和后序遍历都视为更通用算法的特殊情况。具体来说,假设您要进行树遍历并在搜索期间的特定时间执行某些操作(前序、中序或后序)。考虑这一点的一种方法是在访问当前节点之前进行一些前序操作,在访问节点的子节点和节点本身之间进行一些中序操作,以及在访问节点之后进行一些后序操作。这些操作中的任何一个都可以“什么都不做”。例如,一个简单的前序遍历将被指定为

  • 预购步骤:做你想做预购的操作
  • 有序步骤:无操作
  • 后序步骤:无操作

类似地,后序遍历是

  • 预购步骤:无操作
  • 有序步骤:无操作
  • 后序步骤:做你想做后序的操作

Wikipedia 代码的优势在于它允许您执行需要预购和后购步骤的操作。例如,假设您要进行树搜索,但要在每个时间点跟踪已访问但尚未完成的节点。你可以这样做:

  • 预购步骤:将当前节点添加到“活动”列表中。
  • 有序步骤:无操作
  • 后序步骤:从“活动”列表中删除当前节点。

一些算法,例如Tarjan's SCC algorithm,实际上会做这样的事情(尽管承认这是一个图算法并且问题与树有关)。因此,Wikipedia 代码给出了一般情况,其中更常见的情况以及更高级的情况是特殊情况。

希望这会有所帮助!

【讨论】:

  • 我还在听你说的话。但是,我不明白您所说的 Preodder/Postorder/Inorder 操作是什么意思?假设我在深度第一次遍历中位于节点 A,并且 A 有子节点 a1、a2、...、an。那么 Preorder 将是 A, a1, a2, ..., an。是一种操作吗?如果有奇数个孩子,Inorder 操作将如何工作。如果您指定基本搜索的工作方式,我也将非常感激。按照我的想法,我最终在脑海中预购了它。谢谢!
  • 节点的预排序ordering和节点上的预排序操作是有区别的。预购操作只是您在访问每个节点之前所做的事情。如果您在预购操作期间打印出节点,您将在预购中打印出所有节点。 Wikipedia 代码的重点是允许您将前序、后序和中序遍历的元素组合到一个能够执行三者中的任何一个的单一搜索中。
  • @batbrat- 比这更微妙一些。 DFS 以特定顺序遍历树中的节点,通常在向上和向下时多次重新访问节点。访问一个节点通常意味着查看它的子节点并将搜索向下移动到它们中。在访问节点之前执行操作意味着一旦您到达搜索中的节点,您就在该节点上执行一些操作,然后您开始下降到它的子节点。这有意义吗?
  • @batbrat- 我的意思是您访问了节点的一些子节点,但不是全部。也就是说,以节点为根的子树的一部分已经被探索,但不是全部。
  • @batbrat- 是的,在访问子节点之间应用了中序操作。不,你不会在树搜索中使用它。
最近更新 更多