假设您使用的是具有可变长度数组的语言(例如,对于A[i]
中的所有i
使用1..A.length
)并且必须编写一个采用n
的例程(n : 1..8
)长度为n
的可变长度数组中的可变长度项目数组,并且需要调用具有每个可能长度n
项目数组的过程,其中第一个项目是从第一个数组,第二个数组从第二个数组中选择,依此类推。
如果你想要具体的东西可视化,想象你的例程必须采取如下数据:
[ [ 'top hat', 'bowler', 'derby' ], [ 'bow tie', 'cravat', 'ascot', 'bolo'] ... ['jackboots','galoshes','sneakers','slippers']]
并进行以下过程调用(按任意顺序):
try_on ['top hat', 'bow tie', ... 'jackboots']
try_on ['top hat', 'bow tie', ... 'galoshes']
:
try_on ['derby','bolo',...'slippers']
这有时被称为中文菜单问题,对于固定的n
,可以非常简单地编码(例如,对于n
= 3,在伪代码中)
procedure register_combination( items : array [1..3] of vararray of An_item)
for each i1 from items[1]
for each i2 from items[2]
for each i3 from items[3]
register( [ii,i2,i3] )
但如果n
可能会有所不同,会给出如下签名:
procedure register_combination( items : vararray of vararray of An_item)
编写的代码包含一个丑陋的case语句,我用一个更简单的解决方案替换。但我不确定它是最好的(而且肯定不是唯一的)重构方法。
你会怎么做?聪明和令人惊讶是好的,但清晰和可维护性更好 - 我只是通过这个代码而不想回电话。简洁明了的和聪明是理想的。
编辑:我会在其他人有机会回应后,今天晚些时候发布我的解决方案。
预告片:我试图推销递归解决方案,但是他们不会这样做,所以我不得不坚持用HLL编写fortran。
我接下来的答案,张贴在下面。
答案 0 :(得分:2)
递归算法
procedure register_combination( items )
register_combination2( [], items [1:] )
procedure register_combination2( head, items)
if items == []
print head
else
for i in items[0]
register_combination2( head ++ i, items [1:] )
或与尾调用优化的相同,使用数组作为索引,并递增最后一个索引,直到它达到相应数组的长度,然后进行递增。
答案 1 :(得分:1)
递归。
或者,更好的是,尝试使用类似堆栈的结构和while语句来消除递归。
对于你提出的问题(调用带有可变参数的函数),它完全取决于你编写的编程语言;其中许多允许传递变量参数。
答案 2 :(得分:0)
因为他们反对递归(不要问)而且我反对凌乱的案件陈述(事实证明,隐藏a bug)我接受了这个:
procedure register_combination( items : vararray of vararray of An_item)
possible_combinations = 1
for each item_list in items
possible_combinations = possible_combinations * item_list.length
for i from 0 to possible_combinations-1
index = i
this_combination = []
for each item_list in items
item_from_this_list = index mod item_list.length
this_combination << item_list[item_from_this_list]
index = index div item_list.length
register_combination(this_combination)
基本上,我弄清楚有多少组合,为每个组合分配一个数字,然后遍历产生相应组合的数字。我怀疑这不是一个新技巧,但值得了解。
它更短,适用于列表长度的任何实际组合(如果有超过2 ^ 60种组合,它们有其他问题),不是递归的,并且没有the bug。