您将如何在Haskell中表示图形(与旅行商问题相关的图形)

时间:2011-07-28 13:56:15

标签: haskell graph-traversal

在haskell中表示一棵树很容易:

data Tree a = Node Tree a Tree | Leaf a

但这是因为它不需要命令式样式“指针”的概念,因为每个Node / Leaf只有一个父节点。我想我可以将它表示为Maybe Int的列表列表...为那些没有路径的Nothing创建一个表,Just n为那些做...但这看起来真的很难看,而且很笨拙。

5 个答案:

答案 0 :(得分:8)

您可以使用类似

的类型
type Graph a = [Node a]
data Node a = Node a [Node a]

节点列表是该节点的传出(或者如果您愿意,则为传入)边缘。由于您可以构建循环数据结构,因此可以表示任意(多)图形。这种图形结构的缺点是一旦你构建它就无法修改它。要执行遍历,每个节点可能需要一个唯一的名称(可以包含在a中),以便您可以跟踪您访问过的节点。

答案 1 :(得分:6)

免责声明:以下是“打结”技术的无意义练习。如果你想真正使用你的图表,Fgl是要走的路。但是,如果您想知道如何在功能上表示循环数据结构,请继续阅读。

在Haskell中表示图表非常容易!

-- a directed graph

data Vertex a b = Vertex { vdata :: a, edges :: [Edge a b] }
data Edge   a b = Edge   { edata :: b, src :: Vertex a b, dst :: Vertex a b }

-- My graph, with vertices labeled with strings, and edges unlabeled

type Myvertex = Vertex String ()
type Myedge   = Edge   String ()

-- A couple of helpers for brevity

e :: Myvertex -> Myvertex -> Myedge
e = Edge ()

v :: String -> [Myedge] -> Myvertex
v = Vertex

-- This is a full 5-graph

mygraph5 = map vv [ "one", "two", "three", "four", "five" ] where
    vv s = let vk = v s (zipWith e (repeat vk) mygraph5) in vk

这是一个循环的,有限的,递归的,纯函数的数据结构。不是一个非常有效或美丽的,但看,马,没有指针!这是一个练习:包括顶点中的传入边

data Vertex a b = Vertex {vdata::a, outedges::[Edge a b], inedges::[Edge a b]}

很容易构建一个完整的图形,每个边缘有两个(不可区分的)副本:

mygraph5 = map vv [ "one", "two", "three", "four", "five" ] where
    vv s = 
       let vks = repeat vk
           vk = v s (zipWith e vks mygraph5) 
                    (zipWith e mygraph5 vks)
       in vk

但是尝试构建一个每个都有一个副本! (想象一下e v1 v2)中涉及一些昂贵的计算。

答案 2 :(得分:2)

其他人概述的打结技术可以起作用,但是有点痛苦,特别是当你试图动态构建图形时。我认为你描述的方法更实际。我将使用节点类型的数组/向量,其中每个节点类型包含邻居的列表/数组/向量(除了您需要的任何其他数据),表示为适当大小的整数,其中int是节点的索引阵列。我可能不会使用Maybe Int。使用Int,您仍然可以使用-1或任何合适的值作为未初始化的默认值。一旦填充了所有邻居列表并知道它们是好的值,您就不需要Maybe提供的故障机制,正如您所观察到的那样,会产生开销和不便。但是如果您需要完全使用节点指针类型可能包含的所有可能值,那么使用Maybe的模式将是正确的做法。

答案 3 :(得分:2)

最简单的方法是给图中的顶点赋予唯一的名称(可以像Ints一样简单)并使用通常的邻接矩阵或邻居列表方法,即,如果名称是Ints,则使用数组(Int ,Int)Bool,或数组Int [Int]。

答案 4 :(得分:1)

看看this knot-tying technique,它用于创建圆形结构。如果图表包含循环,则可能需要它。

此外,您可以使用邻接矩阵表示图形。

或者您可以在每个节点与入站和出站边缘之间保留映射。

事实上,它们中的每一个在一个环境中都很有用,而在另一个环境中则很痛苦。根据您的问题,您必须选择。