在C语言中高效地排序点数组?

10

我需要对一个点数组进行排序(每个点是一个结构,有两个float类型的值——一个是x,另一个是y),以特定的方式排序。

这些点必须按照一种特殊的方式排序,使得当它们被遍历时,它们形成一个锯齿形的图案,从左上角最高的点开始,向右上角最高的点移动,然后向下到第二左侧最高的点,再到第二右侧最高的点,以此类推。

图示

我需要实现这个排序,以便将任意多边形转换为三角形带数组,然后使用GLes进行绘制。针对这个问题,通过使用指针(例如传递和重新排列指向点结构的指针)或通过直接复制和移动结构中的数据,哪种方法最有效?


3
这不就相当于按y值降序排列,然后决定具有相同y值的节点的顺序吗? - stefan
1
你能澄清一下“top-rightmost”这个术语吗?你是指“最东北方的”,“最右侧点中最高的”,还是“最高点中最右侧的”?(图表似乎排除了第二种情况,但让我们做到彻底。) - Gareth Rees
那么这些点在空间中是固定的,您需要决定点之间的边缘吗? - Jacob
4
在您的例子中,如果与“开始”直接相连的第二个点缺失,那么是否保证存在一种锯齿形模式? - Jacob
2
@Tina Brooks:问题陈述毫无意义。按照从最左边开始连接点1 -> 最右边的点1 -> 第二个最左边的点等顺序通常不会产生锯齿形。如果您对点有额外的保证,您必须说明它们。没有额外的保证,这个问题再次毫无意义。 - AnT stands with Russia
显示剩余3条评论
7个回答

3

我会使用qsort()函数和自定义compare()函数,按照@stefan的建议,先按y值降序排列,然后在x值上交替排序(最大/最小)。


如果一个人关心“真正的Zig-Zag”,那么按最大/最小值交替就是错误的,因为列表中的位置很重要 ;-) - stefan
@Dan:这会如何工作?比较函数如何知道哪个备选方案适用? - Gareth Rees
显然,在比较函数中不能这样做。按y排序,然后决定左/右即可。 - stefan
@Gareth - 我得在这个问题上采取一种不太优美的方式 - 使用(我敢说吗?)全局变量来跟踪是向左还是向右。Daniel有一个非常好的反例,这会使我的解决方案不那么理想。 - Dan Pichelman

2

这类复杂算法的问题在于效率。我需要一些能够快速处理简单形状(不超过10个点)的东西。我找到的最简单的C实现该算法的源代码有超过16,000行。 - Kristina Brooks
好的建议,但它并不能解决 OP 的整个问题(她需要剥离和三角剖分)。 - Gareth Rees
@GarethRees,楼主的问题相当不清楚,这个解决方案确实与问题有关,并让我感到高兴。我对这个答案感激万分! :-) - Notinlist
1
不,Delaunay三角剖分在原始点集已经具有某些便利和良好属性的情况下会是一种严重的过度设计。(只是OP似乎在表述这些属性方面遇到了麻烦)。此外,我怀疑原始问题(OP正在向我们隐藏)是一个多边形三角剖分而不是点集三角剖分。如果是这种情况,Delaunay就不会有太大帮助。OP似乎需要单调分解,然后进行经典的三角剖分。 - AnT stands with Russia

1

我认为您没有给出一个明确的指令。例如,如果这些点看起来像这样,它们应该连接的顺序是什么:

*

         *
                 *
*
    *
    *

2
@Tina Brooks:你发布的图片与 Daniel 所要求的图片不符。 - AnT stands with Russia
@TinaBrooks 在您提供的图片中,有两个点混淆了。从顶部开始的前三个点应该逐渐向右移动。 - Daniel

1

您似乎向我们呈现了一个已经简化过的原始问题版本,认为您正在走向解决方案的正确道路。我可能错了,但看起来并不像是这样。

从您的其他问题来看,似乎您最终正在寻找一种三角测量方法。而且很可能是多边形的三角测量,而不是一组独立的点。如果是这样,我建议您查看一些基本的三角测量算法,比如基于单调分解的算法。您在此处提出的问题实际上看起来像是尝试类似于单调分解的某种[可能是误导性的]方法。


0
我建议直接从结构中移动数据。
点结构的大小仅为8到16个字节(如果浮点数为8个字节,则为16个字节)。如果通过指针对数组进行排序,您将复制几乎相同数量的数据(如果浮点数为4个字节且在64位系统上使用8个字节指针,则为相同数量的数据)。
如果结构体很大,我建议通过指针进行排序。

0

看起来你正在尝试重新发明某种单调多边形链。一些多边形三角剖分方法在wikihere中简要描述,并提供了代码链接。


0

首先,您应该找到点的中位数(基于水平值)。这将把点集分成左右两部分。接下来,根据垂直值对这两个集合进行排序。然后,您可以从每个集合的顶部开始迭代:从左侧集合中取出顶部元素,然后从右侧集合中取出顶部元素,以此类推。

要找到中位数,有一个基于快速排序的简短算法。但比快速排序更快。只需在中位数所在的部分上递归(而不是像快速排序一样在两个部分上递归)。

您也可以反过来做:首先按垂直值排序,然后按水平值拆分(当您有奇数个点时,这可能更好)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接