Data structures Haskell中用于遍历多边形段的数据结构?

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,

我有一个长度为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,2)]


在命令式语言中,我可能会使用(双)链接的数据结构并遍历这些结构。在哈斯凯尔,我想不出一个优雅的表达方式。你会怎么做?

在我们寻找角落之前,让我们后退一步。你想干什么

我有一个长度为1的水平/垂直段的无序列表,它们构建了一个或多个多边形。我现在需要找到每个多边形中所有连接角的列表

“搜索”和“无序列表”并不是一回事,我相信你会意识到这一点!即使在简单的查找中也是如此,但对于您正在做的工作来说,情况更糟。从概念上讲,这更接近于查找重复项,因为它需要将集合的元素彼此关联起来,而不是独立地检查每个元素

所以,你肯定会想要更具结构的东西。一种选择是在完整多边形方面进行更具语义意义的表示,允许简单地遍历一个完整的周界,但我猜您没有可用的信息(例如,如果您试图在此处创建这样的结构)

现在,你在评论中说:

这样做的原因是,这些段以前存储在“集合”中,以便删除重叠段。此表示法保证只有一个段(x,y)-(x+1,y)

这值得进一步思考。
Data.Set
是如何工作的,为什么删除重复项比无序列表更好?最后一位是一种赠品,因为
Data.Set
正是一个有序的集合,所以通过为每个项提供一个唯一排序的表示,您可以获得自动删除重复项和快速查找的综合好处

如上所述,您的实际问题在概念上类似于查找重复项;您需要相邻的线段,而不是查找重叠的线段。使用
Data.Set
也能帮助您吗

唉,它不能。要了解原因,请思考排序是如何工作的。给定两个项X和Y,有三种可能的比较:XY。如果不同的相邻元素的差异达到了可能的最小值,则可以安全地只检查排序集合中相邻的元素。但由于多种原因,这不能推广到线段,最简单的原因是,最多有四个不同的元素可以相邻,这不能用排序序列来描述

希望我的提示足够严厉,您现在想知道允许四个不同元素相邻的排序集合是什么样子,以及它是否允许以
Data.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中的一个。但我不知道,在这种情况下它是否对你有帮助。那么水平段总是进入正空间(右),垂直段也总是进入正空间(上)?@蒂姆·佩里:是的。这样做的原因是,这些段以前存储在“集合”中,以便删除重叠段。此表示法保证只有一个段