Data structures Haskell中用于遍历多边形段的数据结构?
我有一个长度为1的水平/垂直段的无序列表,它们构建了一个或多个多边形。我现在需要找到每个多边形中所有连接角的列表 例如:Data structures Haskell中用于遍历多边形段的数据结构?,data-structures,haskell,Data Structures,Haskell,我有一个长度为1的水平/垂直段的无序列表,它们构建了一个或多个多边形。我现在需要找到每个多边形中所有连接角的列表 例如: [Horizontal (0,0), Vertical (2,0), Horizontal (1,0), Horizontal (2,2), Vertical (2,1)] 表示这样一条线 2 X--X | 1 X | 0 X--X--X 0 1 2 我会寻找角落[(2,0),(2,
[Horizontal (0,0), Vertical (2,0), Horizontal (1,0), Horizontal (2,2), Vertical (2,1)]
表示这样一条线
2 X--X
|
1 X
|
0 X--X--X
0 1 2
我会寻找角落[(2,0),(2,2)]
在命令式语言中,我可能会使用(双)链接的数据结构并遍历这些结构。在哈斯凯尔,我想不出一个优雅的表达方式。你会怎么做? 在我们寻找角落之前,让我们后退一步。你想干什么 我有一个长度为1的水平/垂直段的无序列表,它们构建了一个或多个多边形。我现在需要找到每个多边形中所有连接角的列表 “搜索”和“无序列表”并不是一回事,我相信你会意识到这一点!即使在简单的查找中也是如此,但对于您正在做的工作来说,情况更糟。从概念上讲,这更接近于查找重复项,因为它需要将集合的元素彼此关联起来,而不是独立地检查每个元素 所以,你肯定会想要更具结构的东西。一种选择是在完整多边形方面进行更具语义意义的表示,允许简单地遍历一个完整的周界,但我猜您没有可用的信息(例如,如果您试图在此处创建这样的结构) 现在,你在评论中说: 这样做的原因是,这些段以前存储在“集合”中,以便删除重叠段。此表示法保证只有一个段(x,y)-(x+1,y) 这值得进一步思考。
Data.Set
是如何工作的,为什么删除重复项比无序列表更好?最后一位是一种赠品,因为Data.Set
正是一个有序的集合,所以通过为每个项提供一个唯一排序的表示,您可以获得自动删除重复项和快速查找的综合好处
如上所述,您的实际问题在概念上类似于查找重复项;您需要相邻的线段,而不是查找重叠的线段。使用Data.Set
也能帮助您吗
唉,它不能。要了解原因,请思考排序是如何工作的。给定两个项X和Y,有三种可能的比较:XData.Set
的方式轻松搜索
后者的答案是肯定的,绝对的,而前者的答案是它将是一个更高维的搜索树。简单的二进制搜索树如下所示:
data Tree a = Leaf | Branch a (Tree a) (Tree a)
data Tree a = Leaf | Branch a (Tree a) (Tree a) (Tree a) (Tree a)
…确保在任何分支上,左半部分的所有叶值都小于右半部分的叶值。一个简单的二维搜索树应该是这样的:
data Tree a = Leaf | Branch a (Tree a) (Tree a)
data Tree a = Leaf | Branch a (Tree a) (Tree a) (Tree a) (Tree a)
…其中每个分支代表一个象限,通过在两个轴上进行独立比较进行排序。否则,它的工作原理就像熟悉的一维搜索树一样,对许多标准算法进行简单的转换,并且给定特定的线段,您可以快速搜索任何相邻的线段
编辑:事后看来,我有点太专注于阐述,忘记了提供参考。这根本不是一个新颖的概念,有许多现存的变体:
- 我所描述的被称为a,是二进制搜索树的简单扩展,如
Data.Set
- 同样的概念也适用于区域而不是离散点,查找结束于完全包含或排除的区域。这些是类似的扩展,如
Data.IntSet
- 称为的变体类似于B-树,在某些方面具有有用的性能特征
奇怪的是,除了一个不完整且看似废弃的软件包之外,我一直无法在Hackage上找到任何此类数据结构的实现。如果我正确理解问题描述,每个部分可以参与多达四个可能的角点,每个角点都标识一个特定的补充部分。给定一个线段列表,我们可以沿着列表走下去,看看可能存在哪些两个线段角,然后找出这些线段在哪里相交。由于重复的列表遍历,这是一种非常缓慢的方法,但是如果您只处理大量的段,那么它至少相当简洁
data Segment = Horizontal (Int,Int) | Vertical (Int,Int) deriving (Eq, Show)
example = [ Horizontal (0,0)
, Vertical (2,0)
, Horizontal (1,0)
, Horizontal (2,2)
, Vertical (2,1) ]
corners [] = []
corners (Horizontal (x,y):xs) = ns ++ corners xs
where ns = map cornerLoc . filter (`elem` xs) $
map Vertical [(x,y),(x+1,y),(x,y-1),(x+1,y-1)]
cornerLoc (Vertical (x',_)) = (max x x', y)
corners (Vertical (x,y):xs) = ns ++ corners xs
where ns = map cornerLoc . filter (`elem` xs) $
map Horizontal [(x,y),(x,y+1),(x-1,y),(x-1,y+1)]
cornerLoc (Horizontal (_,y')) = (x, max y y')
最类似于双链接列表的是Haskell中的一个。但我不知道,在这种情况下它是否对你有帮助。那么水平段总是进入正空间(右),垂直段也总是进入正空间(上)?@蒂姆·佩里:是的。这样做的原因是,这些段以前存储在“集合”中,以便删除重叠段。此表示法保证只有一个段