【问题标题】:Non-recursive algorithms for ordered traversing用于有序遍历的非递归算法
【发布时间】:2011-11-08 16:55:04
【问题描述】:

有一个基于以下技术的组合算法系列 - 我们观察结构的某些属性,并使用该属性遍历线性(或接近,无论如何,并不重要)的所有可能/可访问的变体) 时间,没有递归。

例子

字典排列 a1 .. a[n]

  • 找到最后一个 a[k] 使得 a[k] ...
  • 在 a[k + 1] .. a[n] 中找到最小的 a[m] 使得 a[k]
  • 交换 a[m] 和 a[k]
  • 还原 a[k + 1] .. a[n]

n 的 k-子集

  • 从末尾迭代,找到第一个零,前面是 1(第一个 a[k]==0 使得 a[k + 1] == 1)
  • 分配 a[k] = 1
  • 在 a[k] .. a[n] 中计数 1
  • 重新平衡 - 在末尾分配尽可能多的 1,其余设置为零

n 的分区(按降序排列)

  • 找到第一个 k 使得 a[k] > a[k + 1](k = 1 也可以)
  • 增加a[k] = a[k] + 1
  • 求从 k 到最后一个元素的总和
  • 在总和允许的情况下将左邻居增加 1。

我想,这足以说明此类算法的本质。这些以及其他一些示例可以在优秀的、精湛的书籍“Algorithms and Programming: Problems and Solutions”中找到。

我的问题如下。请您在任何领域向我描述此类算法的更多示例。如果您还提供算法本身,那就太好了(换句话说,如上所述,更可取)。也欢迎参考书籍、文章。也欢迎参考相关的理论问题(例如,我只是不知道什么时候可以构建这样的算法,什么时候 - 不)。

提前致谢。

【问题讨论】:

  • 这不可能是开放式的。你只是要求一个随机的算法列表,可以是递归的和非递归的,对吧?这似乎不是一个很好的问题。对此没有“可接受”的答案,是吗?
  • @S.Lott,不同意,我要求一些组合结构的非递归遍历算法。它可以被标记为大名单,但我没有创建标签的特权。如果会有 10 到 15 个不同的例子,那就太好了。无论如何,这比关于语言 X 的隐藏特征、有趣的书等问题更具体(未关闭)。从这个意义上说,它是一种方式,方式不那么开放。
  • “一些组合结构”?你的意思是一个数字列表?这绝不是一种限制。这并不比“隐藏特征”问题更具体,因为没有任何限制,也没有任何人可以确定“接受”什么答案。这只是一个“随机事实列表”问题。

标签: algorithm language-agnostic computer-science


【解决方案1】:

考虑一个算法家族中的算法 A。 A要么已经是迭代的,要么是递归的,通过显式数据结构模拟调用栈,可以转化为等效的迭代算法。参见例如Wikipedia

【讨论】:

  • 那些算法递归和线性非递归是否完全等价?例如,在我的脑海中,线性递归分区并不那么明显。
  • 递归算法和变换迭代算法是完全等价的:它们产生相同的结果并具有相同的时间/空间复杂度。实际的区别在于,对于给定的n,迭代算法通常比递归算法更快,但代价是优雅。
  • @Jiri,我不明白为什么它们都是 O(n)。例如有n!排列,似乎任何产生所有排列的算法都是 Ω((n/e)^n)
  • @Max:感谢您的评论。我认为他对一些线性算法感兴趣以遍历(或生成)例如一种这样的排列。他写道“在线性...时间内遍历所有可能/可访问的变体。”现在,在一遍又一遍地阅读他的问题之后,我不再确定这个问题是关于什么的。我的回答的精髓是“每个递归算法都可以转换为等效的迭代算法”。这对于任何时间复杂度 O(...) 都有效。为了避免进一步的混淆,我正在修改我对这个基本陈述的回答。
【解决方案2】:

这与 Jiri 的回答大致相同,但可能更直接一点:任何可解决的计算问题都可以通过图灵机解决,我认为没有人会将图灵机的功能描述为“递归” ,但作为基于状态的。换句话说,如果有足够的辅助磁带存储、while 循环和 select-case(或等效的分支,例如 if/else 构造),您可以使用基于状态机的方法解决任何问题 - 包括这些枚举问题.

例如,定义一个基于状态的算法来进行二叉搜索树的中序遍历是相当简单的。

  1. 从状态 DL(左下)开始。如果您在 DL 中并且该节点有一个左孩子,则向下移动到它并保持状态 DL;否则,打印节点的内容,如果节点有右孩子,则更改为状态 DR 并移动到右孩子;如果节点没有右子节点,则切换到状态 UR 并移动到父节点。

  2. 如果处于状态 DR,并且您有一个左孩子,则移动到左孩子并更改为状态 DL。否则,如果您有正确的孩子,则打印节点的内容并移动到孩子并留在 DR 中。否则,移动到父节点,切换到状态UL。

  3. 如果在状态UR,打印节点信息,如果有右孩子,移动到它,改变状态为DR;否则,移动到父级并留在 UR。

  4. 如果在状态UL,如果当前节点是其父节点的右子节点,则留在UL并移动到父节点;否则,如果当前节点不是父节点的右子节点,而是左子节点,则切换到状态UR并移动到父节点。如果此节点没有父节点,则终止算法。

无论如何,你明白了。有序树遍历与你得到的一样本质上是递归的;许多(全部?)其他遍历问题可以用遍历一些树来表达,这是一种使用状态机在线性时间内进行中序遍历的方法。你相信这个方法是 O(n) 吗?提示:它访问每个节点不超过 3 次。

【讨论】:

  • 你能告诉我关于这个主题我可以读什么书吗?我已经阅读了很多关于算法的文章,但仍然没有感觉到我看到了全貌。
  • 当然。也许你会喜欢一些关于计算理论的书。虽然大多数“算法”书籍假设例如von Neumann RAM 计算模型,关于计算理论的书籍通常会采用更多样化的方法,并尝试展示哪些问题可以通过什么样的形式机制来解决……这听起来更符合你想要的。查找有关以下主题的书籍:形式语言理论、自动机理论、lambda 演算。探索乔姆斯基层次结构的所有层次——包括语法和自动机。我也可以推荐特定的书...
猜你喜欢
  • 2010-12-01
  • 2018-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多