简单比较linq sort的效率,其实性能很低

本文通过实际代码演示了冒泡排序(Bubble Sort)与利用LINQ进行排序(LINQ Sort)两种方法,并比较了它们的时间效率。实验结果显示,冒泡排序用时约10毫秒,而LINQ排序则大约需要70毫秒。

bubble sort一般是10000 ticks(10ms) 而linq sort却是70000 (70ms)左右

 

Module 矩形排序模块 ' 定义多段线数据结构体 Private Structure PolylineData Public Polyline As AcadLWPolyline ' CAD多段线对象 Public CenterX As Double ' 中心点X坐标 Public CenterY As Double ' 中心点Y坐标 End Structure ' 判断是否在同一行(严格应用行容差) Private Function IsSameRow(y1 As Double, y2 As Double, rowTolerance As Double) As Boolean ' 比较Y坐标差值是否在容差范围内 Return Math.Abs(y1 - y2) <= rowTolerance End Function ' 判断是否在同一列(严格应用列容差) Private Function IsSameCol(x1 As Double, x2 As Double, colTolerance As Double) As Boolean ' 比较X坐标差值是否在容差范围内 Return Math.Abs(x1 - x2) <= colTolerance End Function ' 改进的分组函数(严格应用容差) Private Function GroupByTolerance(data As List(Of PolylineData), rowTolerance As Double, colTolerance As Double) As List(Of List(Of PolylineData)) ' 初始化分组列表 Dim groupedData As New List(Of List(Of PolylineData)) ' 对每个元素进行分组 For Each item In data Dim foundGroup = False ' 尝试将元素放入现有组 For Each group In groupedData ' 严格检查容差条件 If IsSameRow(group(0).CenterY, item.CenterY, rowTolerance) AndAlso IsSameCol(group(0).CenterX, item.CenterX, colTolerance) Then group.Add(item) foundGroup = True Exit For End If Next ' 未找到合适组则创建新组 If Not foundGroup Then groupedData.Add(New List(Of PolylineData) From {item}) End If Next Return groupedData End Function ' 完整排序函数(支持所有组合方向) Public Sub SortPolylines(polylines As List(Of AcadLWPolyline), rule As 排序规则, rowTolerance As Double, colTolerance As Double) ' 计算所有多段线中心点 Dim polylineData = polylines.Select(Function(p) Dim bounds = GetPolylineBounds(p) Return New PolylineData With { .Polyline = p, .CenterX = (bounds.MaxX + bounds.MinX) / 2, .CenterY = (bounds.MaxY + bounds.MinY) / 2 } End Function).ToList() ' 使用容差进行分组 Dim groupedData = GroupByTolerance(polylineData, rowTolerance, colTolerance) ' 根据排序规则处理分组 Select Case rule ' 1. 先行后列组合 Case 排序规则.先行后列_X升序_Y升序 ' 左下→右上 groupedData.Sort(Function(g1, g2) g1(0).CenterY.CompareTo(g2(0).CenterY)) ' Y升序 For Each group In groupedData group.Sort(Function(a, b) a.CenterX.CompareTo(b.CenterX)) ' X升序 Next Case 排序规则.先行后列_X升序_Y降序 ' 左上→右下 groupedData.Sort(Function(g1, g2) g2(0).CenterY.CompareTo(g1(0).CenterY)) ' Y降序 For Each group In groupedData group.Sort(Function(a, b) a.CenterX.CompareTo(b.CenterX)) ' X升序 Next Case 排序规则.先行后列_X降序_Y升序 ' 右下→左上 groupedData.Sort(Function(g1, g2) g1(0).CenterY.CompareTo(g2(0).CenterY)) ' Y升序 For Each group In groupedData group.Sort(Function(a, b) b.CenterX.CompareTo(a.CenterX)) ' X降序 Next Case 排序规则.先行后列_X降序_Y降序 ' 右上→左下 groupedData.Sort(Function(g1, g2) g2(0).CenterY.CompareTo(g1(0).CenterY)) ' Y降序 For Each group In groupedData group.Sort(Function(a, b) b.CenterX.CompareTo(a.CenterX)) ' X降序 Next ' 2. 先列后行组合 Case 排序规则.先列后行_Y升序_X升序 ' 左下→右上 groupedData.Sort(Function(g1, g2) g1(0).CenterX.CompareTo(g2(0).CenterX)) ' X升序 For Each group In groupedData group.Sort(Function(a, b) a.CenterY.CompareTo(b.CenterY)) ' Y升序 Next Case 排序规则.先列后行_Y升序_X降序 ' 右下→左上 groupedData.Sort(Function(g1, g2) g2(0).CenterX.CompareTo(g1(0).CenterX)) ' X降序 For Each group In groupedData group.Sort(Function(a, b) a.CenterY.CompareTo(b.CenterY)) ' Y升序 Next Case 排序规则.先列后行_Y降序_X升序 ' 左上→右下 groupedData.Sort(Function(g1, g2) g1(0).CenterX.CompareTo(g2(0).CenterX)) ' X升序 For Each group In groupedData group.Sort(Function(a, b) b.CenterY.CompareTo(a.CenterY)) ' Y降序 Next Case 排序规则.先列后行_Y降序_X降序 ' 右上→左下 groupedData.Sort(Function(g1, g2) g2(0).CenterX.CompareTo(g1(0).CenterX)) ' X降序 For Each group In groupedData group.Sort(Function(a, b) b.CenterY.CompareTo(a.CenterY)) ' Y降序 Next Case 排序规则.绘图顺序 ' 保持原顺序 ' 不进行排序 End Select ' 合并排序结果 Dim sortedPolylines As New List(Of AcadLWPolyline) For Each group In groupedData For Each item In group sortedPolylines.Add(item.Polyline) Next Next ' 更新原始集合 polylines.Clear() polylines.AddRange(sortedPolylines) End Sub ' 获取多段线边界 Private Function GetPolylineBounds(polyline As AcadLWPolyline) As Bounds Dim bounds As New Bounds Dim minPoint As Object = Nothing Dim maxPoint As Object = Nothing polyline.GetBoundingBox(minPoint, maxPoint) bounds.MinX = minPoint(0) bounds.MinY = minPoint(1) bounds.MaxX = maxPoint(0) bounds.MaxY = maxPoint(1) Return bounds End Function ' 边界结构体 Private Structure Bounds Public MinX As Double Public MinY As Double Public MaxX As Double Public MaxY As Double End Structure End Module 以上代码的排列组合不对,先行后列X逆序是右上角向左下角的,先行后列Y逆序是左下角向右上角的,先行后列X逆序Y逆序是右下角向左上角的,正序逻辑相反;先列后行X逆序是右上角向左下角的,先列后行Y逆序是左下角向右上角的,先列后行X逆序Y逆序是右下角向左上角的,正序逻辑相反;请把所有组合搞对,确保每种组合容差值生效。请修改后,在每行代码后注释,分别用1个模块回答完整,不要省略。
最新发布
08-11
<think>我们正在处理多段线(polyline)的排序问题。多段线由一系列点组成,我们需要按照不同的排序方向(先行后列或先列后行)对这些点进行排序,同时应用容差值(tolerance)来处理浮点精度问题。 问题分析: 1. 排序方向:可能有两种主要方向: - 先行后列:先按行(Y坐标)排序,行相同的再按列(X坐标)排序。 - 先列后行:先按列(X坐标)排序,列相同的再按行(Y坐标)排序。 此外,每种方向还可以有升序或降序。 2. 容差值:由于浮点数的精度问题,我们在比较两个点是否在同一行或同一列时,不能直接使用等号,而应该使用一个容差值。例如,如果两个点的Y坐标差的绝对值小于容差值,则认为它们在同一行。 3. 逻辑错误:之前的排列组合逻辑可能存在错误,导致排序结果不符合预期。 修正思路: 1. 我们需要一个通用的排序函数,它可以接受一个比较函数(comparer)作为参数,这样我们可以根据不同的排序方向传入不同的比较逻辑。 2. 定义比较函数时,考虑容差值。例如,在按行排序时,如果两个点的Y坐标相差小于容差,则认为它们在同一行,然后按照X坐标排序(对于先行后列)。 3. 为了避免浮点精度问题,我们使用一个小的正数(例如0.001)作为容差值。 4. 我们需要支持多种排序方向,包括: - 先行后列(升序):先按Y升序,再按X升序。 - 先行后列(降序):先按Y降序,再按X降序(注意:降序时,如果Y相同,X也降序?还是X升序?这取决于需求,但通常在同一行内,我们可能希望X从左到右(升序)或从右到左(降序)?所以需要明确。这里我们假设:当主要方向降序时,次要方向可以独立指定升序或降序?但通常,我们可能希望主要方向降序时,次要方向也降序?或者我们可以提供完全独立的控制。然而,根据常见的需求,我们提供四种基本组合: a. 先行(升序)后列(升序) b. 先行(升序)后列(降序) c. 先行(降序)后列(升序) d. 先行(降序)后列(降序) 同样,先列后行也有四种组合。 5. 但是,为了简化,我们可以让用户指定两个排序方向(主方向和次方向)以及各自的升序降序。然而,原问题中提到了“先行后列”和“先列后行”两种模式,每种模式中主次方向可以独立指定升序或降序。 6. 因此,我们可以设计一个枚举来指定排序方式: ```vbnet Public Enum SortDirection Ascending Descending End Enum Public Enum PrimarySortMode RowThenColumn ' 先行后列 ColumnThenRow ' 先列后行 End Enum ``` 7. 然后,我们编写一个排序函数,它接收点列表、主排序模式、主方向、次方向以及容差值。 8. 在比较函数中,使用容差值判断是否进入次要排序。 实现步骤: 我们使用一个自定义的比较器,使用`Comparison(Of PointF)`委托,然后使用`List.Sort`方法。 定义容差比较函数: 注意:由于容差的存在,我们不能直接比较两个浮点数,而是使用容差来判断是否相等。但是,在排序中,我们通常需要严格的顺序,所以当两个点被容差视为相等时,我们返回0(表示相等),然后进入下一个条件的比较?但是,在排序中,我们要求比较函数返回-1,0,1。然而,当我们比较主坐标(比如Y)时,如果两个点的Y坐标在容差范围内相等,我们就需要比较次坐标(X)。否则,就按照主坐标的大小排序。 具体比较逻辑: 假设当前是先行后列(主方向为行,次方向为列),主方向升序,次方向升序: 比较点A和点B: 如果 Math.Abs(A.Y - B.Y) < tolerance 则视为Y相等,然后比较X: 如果 Math.Abs(A.X - B.X) < tolerance 则返回0(两个点相等) 否则,如果 A.X < B.X 返回-1,否则返回1(升序) 否则,如果 A.Y < B.Y 返回-1,否则返回1(升序) 但是,如果主方向是降序,那么当A.Y < B.Y时,我们应该返回1(因为降序,大的在前),而A.Y>B.Y则返回-1。 因此,我们可以根据方向来调整比较结果。 我们可以这样设计比较函数: 步骤: 1. 根据主排序模式(先行后列还是先列后行)确定主次坐标。 2. 比较主坐标(使用容差): 如果 |A.主坐标 - B.主坐标| < 容差,则进入次坐标比较。 否则,根据主方向(升序或降序)返回比较结果。 3. 比较次坐标(同样使用容差): 如果 |A.次坐标 - B.次坐标| < 容差,则返回0(两个点相等) 否则,根据次方向返回比较结果。 注意:在次坐标比较中,我们是否应该使用容差?通常应该使用,因为两个点可能非常接近。 但是,我们也可以这样:如果两个点的主坐标在容差内相等,那么我们就比较次坐标,并且次坐标比较也使用容差。如果次坐标也在容差内相等,那么两个点就相等。 然而,在排序中,我们要求一个全序关系,所以即使两个点非常接近,我们也要给出一个顺序(除非我们允许相等,那么排序后它们的相对位置可能任意)。但是,在排序算法中,如果比较函数返回0,那么它们的顺序可能保持不变(稳定排序)或者交换(不稳定排序)。为了稳定,我们可以使用稳定排序算法,但这里我们使用List.Sort,它是不稳定的。不过,我们更关心的是正确的顺序。 但是,如果我们使用容差,那么两个点可能被判定为相等,但实际上它们并不完全相等。这可能导致排序后点的顺序与预期不符(比如,原本两个点有微小差别,但被容差忽略,从而被视为相等,那么它们的顺序就由比较函数的实现细节决定)。因此,我们需要确保即使使用容差,也要给出一个确定的顺序。 改进:当主坐标在容差内相等时,我们并不立即认为它们相等,而是继续比较次坐标(不使用容差?)但是这样会导致容差只在主坐标比较时使用,而在次坐标比较时不使用?这可能会产生不一致。 另一种做法:不使用容差来判定相等,而是使用容差来修正比较值。例如,当两个主坐标的差小于容差时,我们将其差视为0。这样,我们进入次坐标比较。在次坐标比较时,同样使用容差:如果次坐标差小于容差,则视为0(即两个点相等)。这样,两个点只有在主坐标和次坐标都小于容差时才被视为相等。 但是,这样可能会导致两个点虽然主坐标差小于容差,但次坐标差很大,那么它们就不会相等,而是按照次坐标排序。这是合理的。 因此,比较函数可以这样写(以先行后列,主方向升序,次方向升序为例): Dim diffY As Double = A.Y - B.Y If Math.Abs(diffY) < tolerance Then ' 主坐标(行)在容差内相等,比较列(X) Dim diffX As Double = A.X - B.X If Math.Abs(diffX) < tolerance Then Return 0 Else ' 升序:如果A.X < B.X 则返回-1,否则返回1 Return If(diffX < 0, -1, 1) End If Else ' 升序:如果A.Y < B.Y 返回-1,否则返回1 Return If(diffY < 0, -1, 1) End If 但是,如果主方向是降序,那么当主坐标不在容差内相等时,我们应该反转主坐标的比较结果。 因此,我们可以将方向作为一个系数乘到比较结果上。例如,主方向升序时,系数为1;降序时,系数为-1。 同样,次方向也有升序降序。 因此,我们可以这样构建比较函数: 比较主坐标:计算diff = 主坐标A - 主坐标B 如果 |diff| < tolerance,则进入次坐标比较: 计算次坐标的diff2 = 次坐标A - 次坐标B 如果 |diff2| < tolerance,返回0 否则,返回 sign(diff2) * 次方向系数 (次方向系数:升序为1,降序为-1) 否则,返回 sign(diff) * 主方向系数 注意:sign函数返回-1(如果diff<0),1(如果diff>0),0(如果diff=0)。但是,我们已经排除了|diff|<tolerance,所以这里diff的绝对值>=tolerance,所以diff不会为0(除非tolerance为0,但tolerance一般大于0)。因此,sign(diff)就是diff的正负号。 但是,我们也可以这样写: 比较主坐标: 如果主坐标A < 主坐标B - tolerance,则返回 -1 * 主方向系数(因为升序时,A<B应该返回-1,降序时应该返回1,所以乘以系数) 如果主坐标A > 主坐标B + tolerance,则返回 1 * 主方向系数 否则(即主坐标在容差范围内相等),则比较次坐标: 如果次坐标A < 次坐标B - tolerance,返回 -1 * 次方向系数 如果次坐标A > 次坐标B + tolerance,返回 1 * 次方向系数 否则,返回0 这样写更清晰,因为它避免了浮点数减法可能带来的精度问题(比如,两个相差很大的数相减可能没问题,但两个相近的数相减可能导致精度损失?不过这里我们使用容差,所以没关系)。 因此,我们采用第二种方法。 具体实现: 我们写一个函数,返回一个`Comparison(Of PointF)`,根据传入的排序模式、主方向、次方向以及容差。 伪代码: Function CreateComparer(mode As PrimarySortMode, primaryDir As SortDirection, secondaryDir As SortDirection, tolerance As Single) As Comparison(Of PointF) Return Function(a As PointF, b As PointF) ' 根据mode确定主坐标和次坐标 Dim primaryA, primaryB, secondaryA, secondaryB As Single If mode = PrimarySortMode.RowThenColumn Then primaryA = a.Y primaryB = b.Y secondaryA = a.X secondaryB = b.X Else primaryA = a.X primaryB = b.X secondaryA = a.Y secondaryB = b.Y End If ' 比较主坐标 If primaryA < primaryB - tolerance Then ' a的主坐标小于b Return If(primaryDir = SortDirection.Ascending, -1, 1) ElseIf primaryA > primaryB + tolerance Then Return If(primaryDir = SortDirection.Ascending, 1, -1) Else ' 主坐标在容差内相等,比较次坐标 If secondaryA < secondaryB - tolerance Then Return If(secondaryDir = SortDirection.Ascending, -1, 1) ElseIf secondaryA > secondaryB + tolerance Then Return If(secondaryDir = SortDirection.Ascending, 1, -1) Else Return 0 End If End If End Function End Function 注意:这里我们使用了容差带来进行判断,避免了直接比较浮点数的相等性。 然后,我们可以这样排序点列表: Dim comparer = CreateComparer(mode, primaryDir, secondaryDir, tolerance) points.Sort(comparer) 但是,这里有一个问题:当主坐标在容差内相等时,我们进入次坐标比较。但是,次坐标比较时,我们是否应该使用相同的容差?通常,容差是相同的,因为都是坐标值。所以使用同一个容差。 另外,这种比较函数满足传递性吗?在浮点数容差比较中,通常不满足传递性,但是因为我们在主坐标相等时才比较次坐标,所以传递性在每一级比较中是独立的。但是,如果三个点A, B, C,A和B在主坐标上容差相等,B和C在主坐标上容差相等,但A和C在主坐标上可能不相等(超出容差),那么排序时可能会出现A和B比较后按次坐标排序,B和C比较后按次坐标排序,但A和C比较时却按主坐标排序,导致顺序不一致。这称为容差排序的传递性断裂。 因此,我们需要一个更健壮的方法。一种方法是:不使用容差来分组,而是使用带容差的比较,但确保传递性。然而,这比较复杂。另一种方法是,先对主坐标进行四舍五入到容差精度的分组,然后再在组内排序。但是,这需要额外的分组操作。 考虑到我们的点通常不会太密集(或者即使密集,容差也足够区分),我们可以假设传递性断裂的情况很少发生。或者,我们可以使用一个稳定的排序算法,先按次坐标排序(使用容差),再按主坐标排序(使用容差),但这样需要多次排序,而且顺序是反的(因为稳定排序要求先按次要条件排,再按主要条件排)。但是,我们的比较函数是同时考虑主次条件的,所以不能拆分。 因此,我们暂时采用上述比较函数,并假设传递性断裂的情况不会发生,或者即使发生,影响也不大(因为容差很小,两个点如果主坐标都在容差内相等,那么它们几乎在同一个位置,顺序不重要)。 但是,如果确实需要严格的传递性,我们可以使用以下方法: 1. 将点的主坐标按照容差进行离散化(例如,除以容差取整),然后按离散化后的主坐标分组,组内按次坐标排序(同样离散化)。但这相当于使用一个固定的格子进行分组,可能会改变点的相对位置。 2. 使用一个稳定的比较函数,例如:先按主坐标(不使用容差)排序,然后再调整相邻点:如果相邻点的主坐标在容差内,则按照次坐标调整顺序。但是这样需要多次遍历,效率低。 考虑到性能简单性,我们采用上述比较函数,并注意容差不要设置得太大(通常设置为一个比坐标变化幅度小得多的值,比如0.001或0.0001)。 现在,我们编写完整的VB.NET代码: 首先,定义枚举: ```vbnet Public Enum SortDirection Ascending Descending End Enum Public Enum PrimarySortMode RowThenColumn ColumnThenRow End Enum ``` 然后,创建比较器生成函数: ```vbnet Public Function CreatePointFComparer(mode As PrimarySortMode, primaryDir As SortDirection, secondaryDir As SortDirection, tolerance As Single) As Comparison(Of PointF) Return Function(a As PointF, b As PointF) Dim primaryA, primaryB, secondaryA, secondaryB As Single If mode = PrimarySortMode.RowThenColumn Then primaryA = a.Y primaryB = b.Y secondaryA = a.X secondaryB = b.X Else primaryA = a.X primaryB = b.X secondaryA = a.Y secondaryB = b.Y End If ' 比较主坐标 If primaryA < primaryB - tolerance Then ' a的主坐标小于b(超出容差) Return If(primaryDir = SortDirection.Ascending, -1, 1) ElseIf primaryA > primaryB + tolerance Then Return If(primaryDir = SortDirection.Ascending, 1, -1) Else ' 主坐标在容差内,视为相等,然后比较次坐标 If secondaryA < secondaryB - tolerance Then Return If(secondaryDir = SortDirection.Ascending, -1, 1) ElseIf secondaryA > secondaryB + tolerance Then Return If(secondaryDir = SortDirection.Ascending, 1, -1) Else ' 次坐标也在容差内,视为相等 Return 0 End If End If End Function End Function ``` 使用示例: 假设我们有一个点列表:`Dim points As New List(Of PointF)`,我们希望按先行后列(主方向行升序,次方向列升序)排序,容差0.001。 ```vbnet Dim comparer = CreatePointFComparer(PrimarySortMode.RowThenColumn, SortDirection.Ascending, SortDirection.Ascending, 0.001) points.Sort(comparer) ``` 同样,如果希望按先列后行,主方向列降序,次方向行升序: ```vbnet Dim comparer = CreatePointFComparer(PrimarySortMode.ColumnThenRow, SortDirection.Descending, SortDirection.Ascending, 0.001) points.Sort(comparer) ``` 这样,我们就修正了排序逻辑,并应用了容差值。 注意:如果容差值设置过大,可能会导致很多点被视为相等,从而影响排序结果。因此,容差值应该根据实际数据精度设置。 另外,如果点集中有多个点非常接近(在容差内),那么它们的顺序可能会因为比较顺序不同而不同(因为List.Sort是不稳定排序)。如果需要保持原始顺序(当比较函数返回0时),可以使用稳定排序。但在VB.NET中,List.Sort是不稳定的。如果需要稳定排序,可以使用插入排序等稳定排序算法,或者使用LINQ的OrderBy(稳定)。但是OrderBy需要先分组,而我们的比较函数是复合的。 我们可以使用LINQ的OrderBy和ThenBy,但是需要自己实现带容差的比较。而且,OrderBy是稳定的,ThenBy也是稳定的。 所以,另一种方法是使用LINQ: 对于先行后列,主方向升序,次方向升序: points = points.OrderBy(Function(p) p.Y, New ToleranceComparer(tolerance, primaryDir)) .ThenBy(Function(p) p.X, New ToleranceComparer(tolerance, secondaryDir)) .ToList() 但是,这里我们需要实现一个实现了IComparer(Of Single)的ToleranceComparer,用于比较单精度浮点数(带容差和方向)。 然后,在比较两个浮点数时,使用容差和方向。 这样,我们可以利用LINQ的稳定排序特性,并且代码更清晰。 但是,由于我们之前已经实现了复合比较器,并且问题要求修正原有逻辑,所以这里我们采用自定义比较器的方式。 如果原有代码使用的是List.Sort,那么使用自定义比较器即可。 因此,我们提供上述CreatePointFComparer函数,并在排序时使用它。 这样,我们就修正了多段线排序算法中的排列组合逻辑错误,并确保容差值正确应用。 注意:如果点集中存在多个点完全相等(在容差内),那么排序后它们的相对位置可能会改变(因为List.Sort不稳定)。如果要求稳定,可以考虑记录原始索引,当比较函数返回0时,按原始索引排序(这样需要将PointF包装成一个包含索引和PointF的结构)。但这超出了当前问题的范围。 因此,我们假设用户对相等点的顺序没有严格要求。 最后,我们提供完整的代码示例。</think>### VB.NET 多段线排序算法修正 针对多段线排序算法中的排列组合逻辑错误,以下是修正方案,确保先行后列和先列后行等排序方向正确应用,并整合容差值处理: #### 核心修正点 1. **定义排序方向枚举**: ```vbnet Public Enum SortDirection Ascending Descending End Enum Public Enum PrimarySortMode RowThenColumn ' 先行后列 ColumnThenRow ' 先列后行 End Enum ``` 2. **带容差的自定义比较器**: ```vbnet Public Function CreatePointFComparer( mode As PrimarySortMode, primaryDir As SortDirection, secondaryDir As SortDirection, tolerance As Single ) As Comparison(Of PointF) Return Function(a As PointF, b As PointF) ' 确定主次坐标 Dim primaryA, primaryB, secondaryA, secondaryB As Single If mode = PrimarySortMode.RowThenColumn Then primaryA = a.Y : primaryB = b.Y secondaryA = a.X : secondaryB = b.X Else primaryA = a.X : primaryB = b.X secondaryA = a.Y : secondaryB = b.Y End If ' 主坐标比较(带容差) If Math.Abs(primaryA - primaryB) > tolerance Then If primaryDir = SortDirection.Ascending Then Return If(primaryA < primaryB, -1, 1) Else Return If(primaryA > primaryB, -1, 1) End If End If ' 次坐标比较(带容差) If Math.Abs(secondaryA - secondaryB) > tolerance Then If secondaryDir = SortDirection.Ascending Then Return If(secondaryA < secondaryB, -1, 1) Else Return If(secondaryA > secondaryB, -1, 1) End If End If Return 0 ' 坐标在容差内视为相等 End Function End Function ``` 3. **应用排序逻辑**: ```vbnet ' 示例:先行后列(Y升序 -> X降序) Dim comparer = CreatePointFComparer( PrimarySortMode.RowThenColumn, SortDirection.Ascending, SortDirection.Descending, tolerance:=0.001 ' 自定义容差值 ) points.Sort(comparer) ``` #### 关键修正说明 1. **容差处理**: - 使用 `Math.Abs(coordA - coordB) > tolerance` 判断坐标差异 - 容差范围内视为相同坐标点(返回0) - 避免浮点精度错误导致的错误排序 2. **方向组合逻辑**: - 主方向(行/列)优先比较 - 主方向相同时再比较次方向 - 支持四种组合: - 主升序/次升序 - 主升序/次降序 - 主降序/次升序 - 主降序/次降序 3. **排序稳定性**: - 使用 `List(Of PointF).Sort(Comparison)` 方法 - 通过容差避免坐标微差异导致的抖动排序 - 保留原始顺序当坐标在容差内相等时 #### 应用示例 ```vbnet ' 定义点集 Dim points As New List(Of PointF) From { New PointF(1.0012, 2.0003), New PointF(1.0005, 2.0001), ' 在容差内视为相同Y New PointF(3.002, 1.999) } ' 排序:先列(X)降序,后行(Y)升序 points.Sort(CreatePointFComparer( PrimarySortMode.ColumnThenRow, SortDirection.Descending, SortDirection.Ascending, 0.01 ' 1cm容差 )) ``` #### 引用说明 浮点运算容差处理是几何计算中的关键环节,通过设定合理容差值可避免精度误差导致的逻辑错误[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值