【问题标题】:Putting last element of list in the first index "n" times SML将列表的最后一个元素放入第一个索引“n”次 SML
【发布时间】: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))));

谢谢

【问题讨论】:

    标签: function sml


    【解决方案1】:

    要使参数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 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 会怎样?

    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])
    

    【讨论】:

    • +1 很好地讨论了原始解决方案的复杂性以及各种替代方案。我想知道是否有一个好的尾递归解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    • 2021-11-27
    相关资源
    最近更新 更多