【发布时间】:2018-06-05 13:52:31
【问题描述】:
寻找同步和异步递归函数的特定实现,可以用作将未来递归函数转变为平面迭代的起点。
以下是递归函数的两个示例:同步和异步。
我正在寻找的是同时使用 无递归堆栈的实现。
例如,它可能会这样工作:
var output = syncStack(myRecursiveFunctionTurnedIterative, [])
或者,如果这不可能,那么只需使用堆栈重新实现下面的两个函数,这应该是一个足够好的开始。例如
var stack = []
function circularReferences(object, references, stack) {
var output = {}
if (object.__circularid__) return true
Object.defineProperty(object, '__circularid__', { value: id++ })
for (var key in object) {
var value = object[key]
if (value && typeof value == 'object') {
console.log(value)
stack.push(???)
circularReferences()
stack.pop()
if (is) output[key] = '[Circular]'
} else {
output[key] = value
}
}
}
提出这个问题的原因是,多年来我一直在尝试学习如何做到这一点,但从未找到一个 (a) 易于记住如何做,并且 (b) 实用的系统。
同步
var references = {}
var object = {
a: {
b: {
c: {
d: {
e: 10,
f: 11,
g: 12
}
}
}
}
}
object.a.b.c.d.x = object
object.a.b.c.d.y = object.a.b
var id = 1
var x = circularReferences(object, references)
console.log(x)
function circularReferences(object, references) {
var output = {}
if (object.__circularid__) return true
Object.defineProperty(object, '__circularid__', { value: id++ })
for (var key in object) {
var value = object[key]
if (value && typeof value == 'object') {
console.log(value)
var is = circularReferences(value, references)
if (is) output[key] = '[Circular]'
} else {
output[key] = value
}
}
}
异步
var items = [
async1a,
async1b,
async1c
// ...
]
asynca(items, function(){
console.log('done')
})
function asynca(items, callback) {
var i = 0
function next() {
var item = items[i++]
if (!item) return callback()
item(next)
}
}
function async1a(callback) {
// Some stuff...
setTimeout(function(){
if (true) {
var items = [
async2a,
// ...
]
asynca(items, callback)
} else {
callback(null, true)
}
}, 200)
}
function async1b(callback) {
// Some stuff...
setTimeout(function(){
if (true) {
var items = [
async2a,
// ...
]
asynca(items, callback)
} else {
callback(null, true)
}
}, 200)
}
function async1c(callback) {
// Some stuff...
setTimeout(function(){
if (true) {
var items = [
async2a,
// ...
]
asynca(items, callback)
} else {
callback(null, true)
}
}, 200)
}
function async2a(callback) {
return callback()
}
例如,这可能开始看起来像:
var items = [
async1a,
async1b,
async1c
// ...
]
asynca(items, function(){
console.log('done')
}, [])
function asynca(items, callback, stack) {
var i = 0
function next() {
var item = items[i++]
if (!item) return callback()
stack.push(item)
}
}
但这就是我迷路的地方。不确定如何传递堆栈以及一般应如何设置函数。
想知道如何在实践中将它们编写为非递归函数。我见过Way to go from recursion to iteration,但它们都非常理论化。
【问题讨论】:
-
没有一种解决方案适用于所有情况。或者反过来:如果你构建了一个涵盖所有情况的解决方案,那么这个解决方案对于大多数情况来说都太复杂了。你为什么要问这个问题?你在找什么?
-
我只是在寻找它的设计模式。我还没有找到一个有意义的。
-
@LancePollard 您无法以真正通用的方式重写它们的原因之一是您遍历了任意深度,其中每个节点都有任意数量的子节点。你可以到达一半,但最终会发生的是你最终会在
while循环内嵌套while循环(或for在for内),其中循环数与预期匹配最大深度。您可以通过对深度数字进行硬编码来解决其中的一些问题,但要自动执行此操作,无论如何您都需要递归,然后您不妨在此完成工作。 -
@LancePollard 以及涉及回调的异步问题,这根本行不通。如果您的问题的大小保证了序列化和启动另一个进程/工作者所产生的成本,那么有一些方法可以在不破坏堆栈或不完全阻塞主线程的情况下进行递归,甚至推迟到单独的线程。但是如果没有某种形式的代码生成,你将无法展开到任意深度来执行通用任务,而没有某种形式的递归。
-
您可能有兴趣了解即将推出的 asyncitertaor 接口:github.com/tc39/proposal-async-iteration
标签: javascript node.js algorithm asynchronous recursion