Sml 递归计算int list的可能和
我正在努力编写代码,它将计算int list的和。例如,如果我们考虑以下列表Sml 递归计算int list的可能和,sml,smlnj,ml,Sml,Smlnj,Ml,我正在努力编写代码,它将计算int list的和。例如,如果我们考虑以下列表 [[1],[1,5],[7],[2,3,4]] 根据每次选择的整数,我们可以得到不同的可能和: [11,12,13,15,16,17] 有人能给出可能的方法(不需要代码)来解决它吗?我会尝试使用递归循环伪代码来解决它: sum = 0; while (i < arrayOfArrays.length ) { sumUp(arrayOfArrayElements); i ++ } f
[[1],[1,5],[7],[2,3,4]]
根据每次选择的整数,我们可以得到不同的可能和:
[11,12,13,15,16,17]
有人能给出可能的方法(不需要代码)来解决它吗?我会尝试使用递归循环伪代码来解决它:
sum = 0;
while (i < arrayOfArrays.length ) {
sumUp(arrayOfArrayElements);
i ++
}
function sumUp() {
while( j < arrayOfArrayElement.length){
sum = sum + arrayOfArrayElement[j].val
j ++
}
}
sum=0;
而(i
因此,我们调用一个函数,该函数对数组中的每个数组元素求和,并对一个函数中的值求和,该函数对数组中的每个元素调用该函数。lolz
以下是将步骤分解为可读且希望可以理解的部分的尝试
fun sums xss =
let
fun extend xss y = map (fn xs => y :: xs) xss
fun extend' xss ys = foldl (fn (y, b) => extend xss y @ b) [] ys
fun extend'' xss = foldl (fn (xs,b) => extend' b xs) [[]] xss
fun sum xs = foldl op+ 0 xs
in
map sum (extend'' xss)
end
- sums [[1],[1,5],[7],[2,3,4]];
val it = [17,13,16,12,15,11] : int list
显然,大多数函数都可以按正确的顺序将参数作为对,从而直接提供给map和fold函数,而不是将它们包装在匿名函数中。这是我尝试制作只使用列表和模式匹配的尾部递归(类似)算法版本的尝试。它是用OCaml编写的,而不是SML,需要内部列表的升序
let reverse list =
let rec iter list acc :int list = match list with
[] -> acc
| x::xs -> iter xs (x::acc)
in iter list [];;
let listAdd num list =
let rec iter num list acc :int list = match list with
[] -> acc
| x::xs -> iter num xs ((x + num)::acc)
in reverse( iter num list []);;
let listMerge listX listY =
let rec iter listX listY acc : int list = match listX with
[] -> (reverse acc) @ listY
| x :: xs -> match listY with
[] -> (reverse acc ) @ listX
| y :: ys -> match ( compare x y ) with
0 -> iter xs ys ( x::acc )
|(-1) -> iter xs listY ( x::acc )
| 1 -> iter listX ys ( y::acc )
in iter listX listY [];;
let listSums listX listY =
let rec iter listX listY acc = match listX with
[] -> acc
| x :: xs -> iter xs listY ( listMerge acc (listAdd x listY ) )
in iter listX listY [];;
let possibleSums shallowList = match shallowList with
[] -> []
| headList :: lists ->
let rec iter acc lists = match lists with
[] -> acc
| headList :: other -> iter ( listSums acc headList ) other
in iter headList lists;;
这里possibleSums[[1];[1;5];[7];[2;3;4]代码>计算结果为int list=[11;12;13;15;16;17]
因此,基本上合乎逻辑的步骤是:
reverse
函数只是一个实用程序,用于在生成累加器后恢复顺序-尾部递归优化的常用概念
listAdd
函数用于避免在构造摘要时使用map实用程序
listMerge
函数等于set union,可将排序列表用作整数集
listSums
函数,用于将求和映射为两个集合的笛卡尔乘积
posibleSums
函数用于将总和映射到所有集合的完全笛卡尔积的最终级别
该算法不仅通过TCO避免了递归中的堆栈溢出,而且为该计算问题提供了近似最优的解决方案
此外,还可以通过添加不成熟元素和从集合中删除重复元素来进一步改进此解决方案,因此内部集合顺序现在变得无关紧要:
let split lst =
let rec iter lst partX partY = match lst with
[] -> partX,partY
| x::xs -> iter xs partY (x::partX)
in iter lst [] [];;
let rec mergeSort lst = match lst with
[] -> []
|[x] -> [x]
| _ -> let partX,partY = split lst in
listMerge (mergeSort partX) (mergeSort partY);;
let possibleSums shallowList = match shallowList with
[] -> []
| headList :: lists ->
let rec iter acc lists = match lists with
[] -> acc
| headList :: other -> iter ( listSums acc (mergeSort headList) ) other
in iter (mergeSort headList) lists;;
您可以在简单的示例中测试其效率。让我们定义repeat函数来创建重复列表:
let rec repeat elem n = match n with
0 -> []
| _ -> elem :: (repeat elem (n - 1));;
在这种情况下,possibleSums(repeat(repeat 1 30)30)
将立即计算正确的单例答案int list=[30]
。而更直接的解决方案(如Jesper的解决方案)将永远解决这个问题。你的伪代码解决了不同的问题,巴德,还不够清楚吗?嘿,伙计,那么也许你的问题还不够清楚?我想你想得到列表中的整数之和。1)看这个例子,我想你甚至没有看2)你的解决方案甚至不是递归的好吧,我不明白这个问题,谢谢你的提示和好运。你的解决方案使用了一种非常命令式的思维方式,这对于用函数语言SML编码是没有用的。谢谢!您认为不使用map和foldl就可以实现此功能吗?我正在学习一门编程课程,但这些函数还不被允许:)我试图用模式匹配和递归实现它,但完全卡住了……任何事情都是可能的。您可以实现自己的map和fold函数,甚至是它们的专门版本,但是在后面的例子中,您可能会将它们全部内联到一个函数中。不用说太多,我的简单解决方案可以通过“运行”求和进行优化,而不是生成列表列表然后对其求和。然而,无论如何它可能都不匹配:)@Jesper.Reenberg问题不在生成方法中。就整数而言,所有可能的数字组合的集合太大了。该解决方案由于减少了中间结果中的重复次数而速度较快,因此它基于初始数计数和估计结果长度保持多项式复杂性。