【问题标题】:Ocaml - Move last element of list to frontOcaml - 将列表的最后一个元素移到前面
【发布时间】:2011-03-22 21:01:46
【问题描述】:

首先,如果这是一种令人困惑或倒退的方式来实现我想要完成的目标,我深表歉意,但我是“Ocaml 风格”的新手。

我想取出列表的最后一个元素,并将其移到列表的前面,将所有元素上移一个。

例如:有[1;2;3;4;5] -> [5;1;2;3;4]

我知道 Ocaml 中的列表基本上是链表,所以我打算递归遍历列表,找到最后一个元素,然后让该元素的尾部/剩余列表指向列表的头部。

我主要困惑的是如何断开从倒数第二个元素到最后一个元素的链接。在上面的例子中,我想让 5 指向 1,但 4 不再指向 5。

我该如何做到这一点,有没有更简单的方法来查看我完全错过的这个?

【问题讨论】:

  • 作为补充 Joshua Smith/nlucaroni 下面回答的注释,如果您经常想将最后一个元素移到顶部,则列表是错误的表示,因为所有节点都需要重新分配。您可以使用带有可更新尾部的列表——如果您非常确信共享不会引起问题
  • 帕斯卡正确;还有带尾部的拉链。

标签: list recursion linked-list ocaml


【解决方案1】:

您不能“断开链接”,因为 Ocaml 列表是一种持久的数据结构。您不能真正修改列表,因此您必须生成一个新列表,其中包含您想要的顺序的值。

let thelist = [1;2;3;4;5] in
let lnewhead = List.hd (List.rev thelist) in
lnewhead :: (List.rev (List.tl (List.rev b)));;

您也可以在函数中定义它:

let flipper = fun thelist -> 
    (List.hd (List.rev thelist)) :: (List.rev (List.tl (List.rev thelist)));;

val flipper : 'a list -> 'a list = <fun>
# flipper([1;2;3;4;5]);;
- : int list = [5; 1; 2; 3; 4]

【讨论】:

  • 我改变了你对“常量语言”的使用,因为它实际上是特定数据结构的属性——其他数据结构不是持久的,例如哈希表。而且我很确定我以前从未听过“固定语言”这个短语。
  • 顺便说一句,乔希,感谢您的书。我知道你收到了很多抨击......不合理的 IMO。
【解决方案2】:

通过确保 List.rev thelist 只计算一次,可以稍微改进 Joshua 的代码的时间复杂度,如下所示:

let flipper = fun thelist ->
   let r = List.rev thelist
   in (List.hd r) :: (List.rev (List.tl r))

【讨论】:

    【解决方案3】:

    一个安全的实现如下:

    let rot1 l =
      let rec aux acc = function
          [] -> []
        | [x] -> x :: List.rev acc
        | x :: l -> aux (x :: acc) l
      in
      aux [] l
    

    从某种意义上说,传递空列表返回空列表而不是引发异常是安全的。请注意,我强烈反对使用 List.hd 和 List.tl,因为它们可能会失败,并显示一般错误消息。

    此外,对 aux 的递归调用是尾调用(返回之前要做的最后一件事)。 OCaml 编译器将检测到这一点并避免每次函数调用都增加堆栈(并可能引发异常或崩溃)。在处理长列表和递归函数时需要注意这一点。

    为了有效地执行此操作,即在 O(1) 而不是 O(length) 中,您不能使用常规列表。您可以使用标准库中的 Queue 模块或第三方提供的双向链表实现。

    这里是一个使用队列模块的例子:

     let rotate_queue q =
       if not (Queue.is_empty q) then
         let x = Queue.take q in
         Queue.add x q
    
     # let q = Queue.create ();;
     val q : '_a Queue.t = <abstr>
     # Queue.add 1 q;;
     - : unit = ()
     # Queue.add 2 q;;
     - : unit = ()
     # Queue.add 3 q;;
     - : unit = ()
     # Queue.iter print_int q;;
     123- : unit = ()
     # rotate_queue q;;
     - : unit = ()
     # Queue.iter print_int q;;
     231- : unit = ()
     # 
    

    【讨论】:

      【解决方案4】:

      电池库的Dllist module 可能就是您要找的。它是一种命令式列表结构。

      【讨论】:

        猜你喜欢
        • 2013-09-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-05
        • 2022-06-10
        • 2010-12-06
        • 2017-02-16
        • 1970-01-01
        相关资源
        最近更新 更多