【问题标题】:Adjacency list of a tree data structure in HaskellHaskell中树数据结构的邻接表
【发布时间】:2014-07-10 23:49:37
【问题描述】:

我在 Haskell 中定义了以下抽象数据类型:

data Trie = Leaf
          | Node [(Char, Trie)]
          deriving (Eq)

Node 类型是元素列表(c, t),其中c 是从当前节点到t 的边的标签。

现在我想打印出树的邻接列表。具体来说,我需要每行打印一条边,其中一条边的格式为:

n1 n2 c

n1 是源,n2 是目标,c 是边缘的标签。

我可以从我的根节点打印边缘

instance Show Trie where
    show = show' 2 1
        where show' _ _ Leaf = ""
              show' next n1 (Node ts) = unlines $ zipWith (\n2 (c, _) ->
                                                           show n1 ++ " " ++ show n2 ++ " " ++ show c)
                                                    [next..] ts

但现在我不知道如何递归打印孩子。具体来说,如何给子节点编号?

【问题讨论】:

  • 您是否希望为每个节点分配特定的顺序,或者您只想为每个节点分配一个唯一编号?我建议将您的数据类型写为data Trie a = Leaf | Node [(a, Trie)],这样可以轻松编写Trie a -> Trie (a, Int) 类型的函数
  • @user2407038 根节点需要编号为1。其余的顺序无所谓,只要每个节点都有唯一的编号即可。
  • @user2407038 我在讨论写number :: Trie a -> Trie (a, Int)时,深度优先还是广度优先更容易。
  • @user2407038:只是在这种情况下,您需要对 edges 进行编号,而不是对 nodes 进行编号。

标签: haskell


【解决方案1】:

标记节点非常简单,因为 GHC 会为您完成所有繁重的工作:

{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-}

import qualified Data.Traversable as T
import qualified Data.Foldable as F 
import Control.Monad.State 

data Trie a = Leaf a | Node a [(Char, Trie a)] 
  deriving (Eq, Functor, F.Foldable, T.Traversable)

number :: Trie a -> Trie (a, Int)
number = flip evalState 1 . T.mapM (\x -> state $ \n -> ((x,n),n+1))

至于打印 trie,恐怕我不太了解所需的输出。

【讨论】:

  • @user5402:对不起,我忘了flip
【解决方案2】:

我想出了这个解决方案:

import Data.List (foldl')

enum :: Int -> Trie -> ([(Int,Int,Char)],Int)
enum x Leaf = ([],x+1)
enum x (Node pairs)
  = let go (acc,y) (c,t) = (acc',y')
          where acc' = [(x,y,c)] ++ edges ++ acc
                (edges,y') = enum y t
    in foldl' go ([],x+1) pairs

enum 接受起始 id 和 Trie 并返回边列表和下一个可用 id。

-- some examples:

leafs xs = [ (c,Leaf) | c <- xs ]
t1 = Node $ leafs "XYZ"
t2 = Node [('W', t1)]
t3 = Node $ [('A',t2)] ++ leafs "BC"

enum 1 t1 -- ([(1,4,'Z'),(1,3,'Y'),(1,2,'X')],5)
enum 1 t2 -- ([(1,2,'W'),(2,5,'Z'),(2,4,'Y'),(2,3,'X')],6)
enum 1 t3 -- ([(1,8,'C'),(1,7,'B'),(1,2,'A'),(2,3,'W'),(3,6,'Z'),(3,5,'Y'),(3,4,'X')],9)

【讨论】:

    【解决方案3】:

    这是我的尝试:

    data Trie c =
        Leaf
      | Node [(c, Trie c)]
      deriving (Eq)
    
    instance Show c => Show (Trie c) where
      show = show' 1 (\_ -> "\n") where
          show' next cc Leaf = show next ++ "\n” ++ cc (next + 1)
          show' next cc (Node []) = show next ++ "\n” ++ cc (next + 1)
          show' next cc (Node [(c,t)] = show c ++ "(" ++ show next ++ ")” ++ show' (next+1) cc t
          show' next cc (Node (x:xs)) = show' next (\n -> show' n cc $ Node xs) (Node [x])
    

    我使用延续传递样式来跟踪状态。应该有一种方法可以使该代码成为一元代码,或者改用拉链。

    您可以更改叶子或节点的特定位,具体取决于您是否需要对它们进行编号(通过更改next + 1 部分)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-23
      • 1970-01-01
      • 1970-01-01
      • 2012-08-17
      • 2019-11-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多