簡體   English   中英

什么是轉置圖形的“ Haskell方法”?

[英]What is “a Haskell way” to transpose a graph?

假設我有一個表示為父級列表的樹,並且我想反轉邊緣,以獲取每個節點的子級列表。 對於這棵樹-http : //i.stack.imgur.com/uapqT.png-轉換看起來像:

[0,0,0,1,1,2,5,4,4] -> [[2,1],[4,3],[5],[],[8,7],[6],[],[],[]]

但是,它不僅限於圖形轉置。 我還有其他一些問題,可以使用命令式語言通過以下方式解決:遍歷某些源數據數組,並在我了解某些內容時不按順序更新結果數組。

本質上,我的問題是“ Haskell解決這種問題的慣用方式是什么?”。 據我了解,我可以通過可變向量以命令方式進行操作,但是不存在某些純粹的功能方法嗎? 如果沒有,我將如何正確使用可變變量?

最后,我需要它快速運行,這就是O(n)的復雜性,非標准軟件包對我來說不是一個選擇。

值得考慮在Data.VectorData.Array中內部使用變異的純函數,以提高效率(兩個庫中的accum -s以及vector的展開和construct -s)。

當我們在構建期間不關心數組的中間狀態時, accum -s很棒。 它們非常適合轉置圖形,盡管我們必須為節點鍵提供一個范圍:

{-# LANGUAGE TupleSections #-}

import qualified Data.Array as A

type Graph = [(Int, [Int])]

transpose :: (Int, Int) -> Graph -> Graph
transpose range g =
    A.assocs $ A.accumArray (flip (:)) [] range (do {(i, ns) <- g; map (,i) ns})

在這里,我們首先將圖展開到一個鄰接表中,但是要交換索引對,然后將它們累加成一個數組。 它大約與可變數組上的標准命令式循環一樣快,並且比ST monad更為方便。

另外,我們可以只使用IntMap (可能與State monad一起使用), IntMap移植命令式算法,並且對於大多數目的,性能將令人滿意。

幸運的是, IntMap提供了許多高階函數,因此我們(永遠)不會被迫以命令式風格進行編程。 例如, accum有一個類似物:

import qualified Data.IntMap.Strict as IM

transpose :: Graph -> Graph
transpose g =
  IM.assocs $ IM.fromListWith (++) (do {(i, ns) <- g; (i,[]) : map (,[i]) ns})

一種純功能性的方法是使用映射存儲信息,從而產生O(n log n)算法:

import qualified Data.IntMap as IM
import Data.Maybe (fromMaybe)

childrenMap :: [Int] -> IM.IntMap [Int]
childrenMap xs = foldr addChild IM.empty $ zip xs [0..]
  where
    addChild :: (Int, Int) -> IM.IntMap [Int] -> IM.IntMap [Int]
    addChild (parent, child) = IM.alter (Just . (child :) . fromMaybe []) parent

您還可以使用命令式解決方案,並使用ST monad (顯然為O(n))使事情保持純凈,但是命令式代碼在某種程度上模糊了主要思想:

import Control.Monad (forM_)
import Data.Array
import Data.Array.MArray
import Data.Array.ST

childrenST :: [Int] -> [[Int]]
childrenST xs = elems $ runSTArray $ do
    let l = length xs
    arr <- newArray (0, l - 1) []
    let add (parent, child) =
          writeArray arr parent . (child :) =<< readArray arr parent
    forM_ (zip xs [0..]) add
    return arr

這種方法的一個缺點是索引超出范圍,只是失敗了。 另一個是您遍歷列表兩次。 但是,如果您在各處使用數組而不是列表,則無所謂。

暫無
暫無

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

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