簡體   English   中英

純函數式編程語言中的雙重鏈接列表

[英]Doubly Linked List in a Purely Functional Programming Language

如何用純函數式語言編寫雙向鏈表? 也就是說,像Haskell這樣的東西,你不在Monad,所以你沒有變異。 可能嗎? (單鏈表很明顯很簡單)。

在純函數式語言中,雙向鏈表並不那么有趣。 雙向鏈表的想法是能夠抓住節點並朝任一方向前進,或者能夠拼接到列表的中間。 在純函數式語言中,您最好使用以下兩種數據結構之一:

  • 一個單獨鏈接的列表,中間有一個指針,您可以從左側或右側(Huet的“Zipper”的變體)

  • 手指樹,是由Ralf Hinze和Ross Paterson發明的令人興奮的數據結構。

我是拉鏈的忠實粉絲; 它在很多情況下都很有用。

有很多方法。

如果你不想在構建它之后改變雙向鏈表,你就可以依靠懶惰來“打結”。

http://www.haskell.org/haskellwiki/Tying_the_Knot

如果你想要一個可變的雙鏈表,你需要以某種方式偽造引用 - 或者使用真正的引用 - 這是Oleg Kiseylov提出的技巧並在這里實現:

http://hackage.haskell.org/packages/archive/liboleg/2009.9.1/doc/html/Data-FDList.html

有趣的是,請注意前者從根本上依賴懶惰來取得成功。 你最終需要突變或懶惰來打結。

我會重申musicfan的問題:“你到底需要什么呢?” 正如Norman Ramsey所說:如果你需要多向遍歷,那么拉鏈就更容易了; 如果你需要快速拼接,手指樹很好用。

但是,只是看它看起來如何......

import Control.Arrow
import Data.List

data LNode a = LNode { here :: a, prev :: LList a, next :: LList a }
type LList a = Maybe (LNode a)

toList :: LList a -> [a]
toList = unfoldr $ fmap $ here &&& next

fromList :: [a] -> LList a
fromList l = head nodes where
    nodes = scanr ((.) Just . uncurry LNode) Nothing $ zip l $ Nothing : nodes

append :: LList a -> LList a -> LList a
append = join Nothing where
    join k (Just a) b = a' where
        a' = Just $ a { prev = k, next = join a' (next a) b }
    join k _ (Just b) = b' where
        b' = Just $ b { prev = k, next = join b' Nothing (next b) }
    join _ _ _ = Nothing

在OCaml中,對於循環簡單鏈接列表,您可以始終執行以下操作:

type t = { a : t Lazy.t }

let cycle n =
  let rec start = {a = lazy (aux n) }
  and aux = function
    | 0 -> start
    | n -> { a = lazy (aux (n-1))}
  in start

對於雙鏈表,我想可以做類似的事情。 但是,在打字時,你必須依賴懶惰和記錄是友好的結構。 快速而骯臟的循環雙向鏈表:

  type 'a t = { data : 'a; before : 'a t Lazy.t; after : 'a t Lazy.t }

  let of_list l =
    match l with [] -> assert false | hd::tl ->
    let rec start = { data = hd; before = last; after = next }
    and couple = lazy (aux (lazy start) hd) 
    and next = lazy (Lazy.force (fst (Lazy.force couple)))
    and last = lazy (Lazy.force (snd (Lazy.force couple)))
    and aux before = function
    | [] -> (lazy start), before
    | hd::tl -> let rec current = lazy { data = hd; before = before; after = after }
                   and couple = lazy (aux current tl) 
                   and after = lazy (Lazy.force (fst (Lazy.force couple)))
                   and last = lazy (Lazy.force (snd (Lazy.force couple))) in
                   current, last
    in start

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM