我正在处理图形,我创建了一个名为vertex的自定义类型。
type Vertex = (Int, [Vertex])
此类型是一对采用Int
,它是特定顶点的索引号,[Vertex]
是与此顶点相邻的顶点列表。
然后我创建了图表的邻接列表。我遇到了这个问题。如何为这个给定的顶点类型定义相邻顶点列表?
让我有一个带有两个顶点的图形。我们称之为 1 和 2 。他们之间有一个优势。因此,顶点 1 与顶点 2 相邻,反之亦然。 现在,我的邻接列表看起来像这样:
adjacencyList :: [Vertex]
adjacencyList = [ (1, [ (2, [ (1, [ (2, [ (1, …) ]) ]) ]) ])
, here would go the vertex 2 ]
因为您可以看到问题是我的顶点类型的递归定义 - 顶点 1 具有相邻顶点 2 其相邻顶点 1 它有相邻的顶点 2 ,它有相邻的顶点 1 等。这个定义对我来说似乎是无限的。
在像C ++这样的命令式语言中,我会用指针解决这个问题。 但是我怎样才能在Haskell中克服这个问题?
答案 0 :(得分:3)
这就是为什么懒惰很方便。你可以做到
setStrokeStyle(1)
如果你来自c ++世界,这段代码可能会显得神秘莫测。但是,它实际上比c ++中的相互递归函数更奇怪。 (事实上,这个想法几乎是一样的。)
答案 1 :(得分:1)
对我来说,每个顶点都应该负责了解它的邻居,这似乎很奇怪。这种风格可能适用于C ++或其他使用引用相等的语言,但它在Haskell中确实很尴尬。
尝试对此图形进行建模:
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe (fromMaybe)
type Vertex = Int
type Graph = Map Vertex [Vertex] -- each vertex mapped to its 'out-neighbors'
然后您不需要构建那些复杂的邻接列表。获取任何顶点的邻居很简单:
neighbors :: Vertex -> Graph -> [Vertex]
neighbors v g = fromMaybe [] (Map.lookup v g)
关键是标记为Vertex
的每个1
都是相同的Vertex
,无论它是否与内存中的对象相同。
为了添加连接,我们可以使用insertWith
中的Data.Map
函数和list append:
connect :: Vertex -> [Vertex] -> Graph -> Graph
connect = Map.insertWith (++)
当然,我们需要能够创建一个空图表:
empty :: Graph
empty = Map.empty
请记住,这是针对有向图。无向图需要一些额外的注意来保留其不变量。此外,使用相邻顶点的列表意味着我们可以从顶点到另一个顶点具有多个边。我们可以使用Sets来删除此行为。
我希望这会有所帮助。