功能:构造整数列表1..n

时间:2009-05-06 09:15:15

标签: functional-programming recursion scheme sml

这不是作业。我自己学习标准ML。我也知道一点Scheme,所以这个问题应该用两种语言来回答。

我的自我赋值是编写一个构造从1到n的整数列表的函数。例如,list(7)应返回[1,2,3,4,5,6,7]。 O(n)解决方案是理想的。

在线性时间内反向构建列表很容易(即[n,n-1,...,1]):

fun list 1 = 1::nil
|   list n = n::list(n-1);

我构建前进列表的尝试是O(n ^ 2),因为追加操作是线性的。

fun list 1 = 1::nil
|   list n = list(n-1) @ n::nil;

我的下一次尝试是从结尾到前面(从右到左)建立一个列表,从nil开始,将n连接到前面,然后向后递归到1.但它根本不起作用。< / p>

fun list n = (if n = 1
              then 1
              else list(n-1) :: n) :: nil;

有些东西让我觉得我需要一个帮助函数来构建在递归中使用的未终止列表,但我很难过。

6 个答案:

答案 0 :(得分:4)

使用Basis Library

fun list n = List.tabulate (n, fn x => x + 1)

使用简单的累加器,

val list =
    let fun list' k 0 = k
          | list' k n = list' (n::k) (n-1)
    in list' nil end

这构建了一个从尾端开始的列表。如果你想到减少,

   list 5
=> list' nil 5
=> list' (5::nil) 4
=> list' (4::5::nil) 3
=> list' (3::4::5::nil) 2
=> list' (2::3::4::5::nil) 1
=> list' (1::2::3::4::5::nil) 0
=> [1, 2, 3, 4, 5]

可替换地,

  

有些东西让我觉得我需要一个帮助函数来构建在递归中使用的未终止列表,但我很难过。

未终止列表的表示是一个获取列表并返回列表的函数:例如,为了表示10::_,您可以使用fn x => 10::x

fun list n =
    let fun list' m k = if m > n then k nil else
                        list' (m+1) (fn x => k (m::x))
    in list' 1 (fn x => x) end

再一次,如果你想到减少,

   list 5
=> list' 1 (fn x => x)
=> list' 2 (fn x => (fn x => x) (1::x))
=> list' 3 (fn x => (fn x => (fn x => x) (1::x)) (2::x))
=> list' 4 (fn x => (fn x => (fn x => (fn x => x) (1::x)) (2::x)) (3::x))
=> list' 5 (fn x => (fn x => (fn x => (fn x => (fn x => x) (1::x)) (2::x)) (3::x)) (4::x))
=> list' 6 (fn x => (fn x => (fn x => (fn x => (fn x => (fn x => x) (1::x)) (2::x)) (3::x)) (4::x)) (5::x))
=> (fn x => (fn x => (fn x => (fn x => (fn x => (fn x => x) (1::x)) (2::x)) (3::x)) (4::x)) (5::x)) nil
=> (fn x => (fn x => (fn x => (fn x => (fn x => x) (1::x)) (2::x)) (3::x)) (4::x)) (5::nil)
=> (fn x => (fn x => (fn x => (fn x => x) (1::x)) (2::x)) (3::x)) (4::5::nil)
=> (fn x => (fn x => (fn x => x) (1::x)) (2::x)) (3::4::5::nil)
=> (fn x => (fn x => x) (1::x)) (2::3::4::5::nil)
=> (fn x => x) (1::2::3::4::5::nil)
=> [1, 2, 3, 4, 5]

在这种情况下,算法的结构可以使普通数据结构足以满足累加器的要求,但使用延续作为累加器是一种非常强大且有用的技术,不应该被忽视。

答案 1 :(得分:3)

一种经典的方法是以相反的顺序构建它,然后反转它。那是O(n)的两倍,当然就像O(n)一样。

答案 2 :(得分:3)

这是一个解决方案:

fun list n =
  let
    fun f 1 m = m::nil
    |   f n m = m::f (n-1) (m+1)
  in
    f n 1
  end;

答案 3 :(得分:3)

这是一个使用辅助函数和尾递归启用累加器的版本:

fun list n =
  let
    fun aux i acc = 
      if i > 0
      then aux (i-1) (i::acc)
      else acc
  in
    aux n nil
  end;

答案 4 :(得分:2)

对于像这样的列表问题,解决更普遍的问题通常更容易。

  

如何按顺序构建包含整数 i 的列表,使 n&lt; = i&lt; = m

该解决方案具有基本案例和归纳步骤:

  • 如果 n&gt; m ,列表为空。

  • 如果 n&lt; = m ,解决方法是编写 n ,然后解决问题 n + 1&lt; = i &lt; = m

这种观点很快就会形成清晰,简洁的ML代码(已测试):

fun range n m = if n > m then [] else n :: range (n+1) m
fun list n = range 1 n

答案 5 :(得分:0)

(define (iota n)
  (let f ((i n)(a '())
    (if (zero? i)
        (reverse a)
        (f (- i 1) (cons i a)))))