3

这不是家庭作业。我正在自学标准机器学习。我也懂一点 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;

我的下一个尝试是通过从 ni​​l 开始,将 n 附加到前面,然后向后递归到 1 来构建从末端到前面(从右到左)的列表。但它根本不起作用。

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

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

4

6 回答 6

4

使用基础库

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]

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

于 2009-05-06T13:52:34.640 回答
3

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

于 2009-05-06T09:16:44.397 回答
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;
于 2009-05-06T09:37:03.600 回答
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;
于 2009-05-06T12:45:24.893 回答
2

对于这样的列表问题,通常更容易解决更一般的问题。

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

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

  • 如果n > m,则列表为空。

  • 如果n <= m,解决方案是写n后跟问题n+1 <= i <= m的解决方案。

此视图可快速生成清晰、简洁的 ML 代码(经过测试):

fun range n m = if n > m then [] else n :: range (n+1) m
fun list n = range 1 n
于 2009-05-07T03:50:42.550 回答
0
(define (iota n)
  (let f ((i n)(a '())
    (if (zero? i)
        (reverse a)
        (f (- i 1) (cons i a)))))
于 2009-05-06T12:39:43.740 回答