将列表的最后一个元素放在第一个索引中“n”乘以SML

时间:2017-09-19 20:06:07

标签: function sml

我正在尝试将列表的最后一个元素放在列表的前面,同时将其余元素按相同的顺序保持N次。我可以用这个函数做一次,但我想在函数中添加另一个参数,以便函数调用N次。

代码:

fun multcshift(L, n) = 
if null L then nil
else multcshift(hd(rev L)::(rev(tl(rev L))));

由于

1 个答案:

答案 0 :(得分:2)

要使参数 n 有效,您需要递归。你需要一个基本案例,此时函数不再调用自身,并且需要一个递归的情况。对于这个函数,一个很好的基本情况是 n = 0 ,意思是“将前面的最后一个字母移动0次”,即返回 L 而不进行修改。

fun multcshift(L, n) = 
  if n = 0
    then L
    else multcshift( hd(rev L)::rev(tl(rev L)) , n - 1 )

此功能的运行时间非常糟糕:对于每个 n ,将列表反转三次!

您可以通过两次调用rev L来保存至少其中一个列表撤消。 E.g。

fun multcshift (L, 0) = L
  | multcshift (L, n) =
    let val revL = rev L
    in multcshift ( hd revL :: rev (tl revL) , n - 1 ) end

那些hd revLrev (tl revL)似乎是有用的库函数。将函数应用于自己的输出 n 次的过程看起来也是一个很好的库函数。

(* Return all the elements of a non-empty list except the last one. *)
fun init [] = raise Empty
  | init ([_]) = []
  | init (x::xs) = x::init xs

(* Return the last element of a non-empty list. *)
val last = List.last

(* Shift the last element of a non-empty list to the front of the list *)
fun cshift L = last L :: init L

(* Compose f with itself n times *)
fun iterate f 0 = (fn x => x)
  | iterate f 1 = f
  | iterate f n = f o iterate f (n-1)

fun multcshift (L, n) = iterate cshift n L

但是运行时间同样糟糕:对于每个 n ,每次都要调用lastinit。它们都是 O(| L |),就像rev一样。

您可以通过一次执行多个班次来克服这种复杂性。如果你知道你将移动一个元素 n 次,你也可以转移 n 元素。移动 n 元素相当于删除 | L | - n 来自列表前面的元素,并将它们附加在后面。

但是如果你被要求转移 n 元素 n> | L | ?然后len - n为否定,List.dropList.take都将失败。您可以通过断定 | L | 元素的任何完全移位对结果没有影响并且 n(mod | L |)就足够了。如果 n< 0

fun multcshift ([], _) = raise Empty
  | multcshift (L, 0) = L
  | multcshift (L, n) =
    let val len = List.length L
    in List.drop (L, len - n mod len) @
       List.take (L, len - n mod len) end

有很多值得测试的角落案例:

val test_zero = (multcshift ([1,2,3], 0) = [1,2,3])
val test_empty = (multcshift ([], 5); false) handle Empty => true | _ => false
val test_zero_empty = (multcshift ([], 0); false) handle Empty => true | _ => false
val test_negative = (multcshift ([1,2,3,4], ~1) = [2,3,4,1])
val test_nonempty = (multcshift ([1,2,3,4], 3) = [2,3,4,1])
val test_identity = (multcshift ([1,2,3,4], 4) = [1,2,3,4])
val test_large_n = (multcshift [1,2,3,4], 5) = [4,1,2,3])
val test_larger_n = (multcshift [1,2,3,4], 10) = [3,4,1,2])