【发布时间】:2017-09-20 16:43:08
【问题描述】:
我试图将列表的最后一个元素放在列表的前面,同时将其余元素保持 N 次相同的顺序。我可以用这个函数做一次,但我想在函数中添加另一个参数,以便函数调用 N 次。
代码:
fun multcshift(L, n) =
if null L then nil
else multcshift(hd(rev L)::(rev(tl(rev L))));
谢谢
【问题讨论】:
我试图将列表的最后一个元素放在列表的前面,同时将其余元素保持 N 次相同的顺序。我可以用这个函数做一次,但我想在函数中添加另一个参数,以便函数调用 N 次。
代码:
fun multcshift(L, n) =
if null L then nil
else multcshift(hd(rev L)::(rev(tl(rev L))));
谢谢
【问题讨论】:
要使参数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,将列表反转3次!
您可以通过不调用rev L 两次来保存至少一个列表反转。例如
fun multcshift (L, 0) = L
| multcshift (L, n) =
let val revL = rev L
in multcshift ( hd revL :: rev (tl revL) , n - 1 ) end
那些hd revL 和rev (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,分别调用一次 last 和 init。他们都是O(|L|),就像rev。
您可以通过一次执行多个班次来克服这种复杂性。如果你知道你会移动一个元素 n 次,你不妨移动 n 个元素。移动 n 个元素相当于删除 |L| - 列表前面的 n 个元素并将它们附加到后面。
但是,如果您被要求将 n 个元素移到 n > |L| 的位置怎么办?那么len - n 是负数,List.drop 和List.take 都会失败。您可以通过以下结论来解决此问题:|L| 元素的任何完全移位都不会影响结果,并且使用 n (mod |L|) 就足够了。如果 n 会怎样?
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])
【讨论】: