Resuming a recursive function from a saved state
我有一个递归函数,该函数从一组n中产生所有长度为k的组合。通常称为" nCk"(" n选择k")。我希望将其设置为较大的值(56C22),以产生2,142,582,442,263,900个结果。由于实施方面的限制(我必须使用VBScript,并且无法保持登录计算机的时间超过我的工作时间),所以我将无法让它一劳永逸地完成。因此,我想定期保存该函数的当前状态并在以后恢复它...但是我似乎无法弄清楚该怎么做。递归困扰着我从逻辑上进行思考的能力。
我在这里仔细研究了建议的解决方案,否则搜索了"恢复递归函数"之类的方法,但无济于事。我希望通过一些指针(不是编程语言双关语)来使我走上正确的Rails。
在不包含实际代码的冗长解释中,首选实际算法(伪代码很好)。如果您想实际编写代码,我对C,C,Pascal,VB,JavaScript和VBScript最为熟悉(并且如上所述,目前正在使用VBScript)。
这是我的递归函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | function nCk(aSet, iSetIndex, aSubset, iSubsetIndex) 'Found result if (iSubsetIndex > ubound(aSubset)) then log"output.txt", join(aSubset), 1, false exit function end if 'No more characters available if (iSetIndex >= ubound(aSet) + 1) then exit function end if 'With aSet[iSetIndex] aSubset(iSubsetIndex) = aSet(iSetIndex) nCk aSet, iSetIndex + 1, aSubset, iSubsetIndex + 1 'Without nCk aSet, iSetIndex + 1, aSubset, iSubsetIndex end function 'nCk |
仅供参考:我今年50岁;这不是功课。
存储递归并不是一件容易的事,因为要恢复该操作,您将需要还原堆栈,这不是一件简单的任务。我将使用一个迭代算法,它不像递归那样优雅。但是,如果需要中断/继续计算,它会奏效。
一个想法可能是:
作为算法(首先,用于遍历所有子集):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | def calc_subsets(state, N):#N - number of elements in the original set while True: #just iterate if storeFlag:#you need to set this flag to store and interrupt store(state) return if len(state)==N and state[-1]!=-1: #a full subset is reached evaluate(state) state.append(-1)#mark for unwind if state[-1]==-1:#means unwind state state.pop() if not state: #state is empty return #unwinded last element, we are done if state[-1]==1:#there is noting more to be explored state[-1]=-1#mark for unwind in the next iteration else:# = 0 is explored, so 1 is the next to explore state[-1]=1 else: #means explore state.append(0) # 0 is the first to explore |
1 2 | def evaluate(state): print state |
要打印3个元素的所有子集,应调用:
1 2 3 4 5 6 7 8 9 10 | calc_subsets([0], 3) >>> [0, 0, 0] [0, 0, 1] [0, 1, 0] [0, 1, 1] [1, 0, 0] [1, 0, 1] [1, 1, 0] [1, 1, 1] |
并仅打印第二部分:
1 2 3 4 5 6 | calc_subsets([0,1,1,-1], 3) >>> [1, 0, 0] [1, 0, 1] [1, 1, 0] [1, 1, 1] |
现在,该算法可以调整为仅迭代具有给定基数的所有子集。为此,必须跟踪当前子集中的元素数量,并在达到要求的子集大小时触发展开(通过将-1推入状态向量)。
我不确定您的特定语言实现方式,但我相信在某些情况下将递归转换为迭代是很容易的。当您有一个显式堆栈时,将其写入磁盘并从上次中断的地方接起来应该不太复杂。
一般示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | stack = [[argument1,argument2,argument3,...etc.]] while stack is not empty current_parameters = stack.pop aSet = current_parameters[0] iSetIndex = current_parameters[1] ...etc. if ... else ... // push to stack instead of calling nCk stack.push([aSet, iSetIndex + 1, aSubset, iSubsetIndex + 1]) if it's time to go home write stack to disc break |