Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/github/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Excel 优化算法(嵌套用于…下一个循环)_Excel_Algorithm_Vba_Optimization - Fatal编程技术网

Excel 优化算法(嵌套用于…下一个循环)

Excel 优化算法(嵌套用于…下一个循环),excel,algorithm,vba,optimization,Excel,Algorithm,Vba,Optimization,我编写了以下程序,从XYZ点列表(分别为第2列、第3列和第4列)中提取具有给定距离和给定高程差的点对。问题是它包含一个嵌套的for循环,我认为这会导致太多的迭代,因此对于大量的点(>1000),例程需要花费不合理的时间来完成。如何优化此算法 问候, 胺 你应该考虑在 o(Logn+k)中使用最近邻居的帮助,其中k是有效邻居< /代码>,如果超过了邻居,你可以停止找到邻居。这将在O(n(logn+k))中工作,而不是蛮力算法给出的O(n^2)。如果需要评估每个点之间的距离和高度,您没有很多选项来优

我编写了以下程序,从XYZ点列表(分别为第2列、第3列和第4列)中提取具有给定距离和给定高程差的点对。问题是它包含一个嵌套的for循环,我认为这会导致太多的迭代,因此对于大量的点(>1000),例程需要花费不合理的时间来完成。如何优化此算法

问候,


你应该考虑在<代码> o(Logn+k)中使用最近邻居的帮助,其中k是有效邻居< /代码>,如果超过了邻居,你可以停止找到邻居。这将在

O(n(logn+k))
中工作,而不是蛮力算法给出的
O(n^2)

如果需要评估每个点之间的距离和高度,您没有很多选项来优化算法

  • 你可以像Vikram Bhat说的那样,在3d树中对数据进行排序,但这意味着需要花费计算时间来构建树,如果你只使用一次树,我不确定你会获得很多时间

  • 通过删除Sqr(),可以更快地计算距离。
    ((x2-x1)²+(y2-y1)²)=(距离)²
    由于您正在寻找一个固定的距离,因此一次计算(距离)²然后在每个if中使用该值会更快。
    在您的情况下(距离=1,则距离²=1),您的测试将变成:

    ((Cells(c2, 2) - Cells(c1, 2)) ^ 2 + (Cells(c2, 3) - Cells(c1, 3)) ^ 2) = 1
    
    您还可以使用距离近似算法:

  • 另一个优化是在距离之前检查高程时交换两个if条件。因为这种情况下计算速度更快,并且可能避免计算距离,所以对于您的算法来说,这可能是一个很好的加速

  • 您的代码已修改:

    Sub Test1()
    
    Columns("H:K").Select
    Selection.ClearContents
    c3 = 2
    For c2 = 2 To 10
    
    For c1 = c2 + 1 To 10
        If ((Cells(c2, 2) - Cells(c1, 2)) ^ 2 + (Cells(c2, 3) - Cells(c1, 3)) ^ 2) = 1 Then
            If Abs(Cells(c1, 4) - Cells(c2, 4)) = 10 Then
                    Cells(c3, 8) = Cells(c1, 2)
                    Cells(c3, 9) = Cells(c1, 3)
                    Cells(c3, 10) = Cells(c2, 2)
                    Cells(c3, 11) = Cells(c2, 3)
                    c3 = c3 + 1
            End If
        End If
    Next c1
    
    Next c2
    
    End Sub
    

    亲爱的Vikram,感谢您的回复。如果你不介意的话,我有三个问题:1)在你提供的方程中,变量O,n和k代表什么?2) kd树是一个使用标准VB语法的可编程任务,还是只能通过外部方式实现?3)另一个优化是否涉及引用数组而不是单元格或范围?@user32882我不知道VB中有任何kd树库,但这不会阻止你,因为python、ruby中有很多这样的库,C++,从中可以生成一个过程,然后通过输出文件来回忆输出。我建议您使用现有的库。@user32882如果您不知道O、n、k变量,则它们对您来说并不重要,因为它们用于我认为您不熟悉的时间复杂性分析。我刚才提到它们是为了告诉您,使用kd tree的解决方案可以快多少,所以如果您不熟悉它们,请不要担心。@user32882如果单元在内存中,那么我认为如果您使用数组,则不会有任何改进,所以请继续使用单元。@Vikramhat好的,好的,但不管算法是什么,如果避免单元格引用,它的运行速度将提高大约十倍。如文所述,它的速度将是惊人的缓慢。我的第二点是,“如果细胞在内存中”是一个模糊的说法。当然,单元在内存中,问题是访问它们的过程和开销。但是无论如何,建议是存在的,因为有一个VBA标记。如果您将数据读入一个变量数组并在不引用工作表的情况下进行计算,它将运行得更快。它就像,块读取,计算,块写回输出范围。首先将变量数组加载到Double(或Long,如果它们是整数)的2D数组中的开销可能是值得的。此外,c1、c2和c3也应明确声明为Long。它们是当前速度较慢的变体。是的,性能代码应始终使用类型化变量,而不是每次访问时都检查类型
    Sub Test1()
    
    Columns("H:K").Select
    Selection.ClearContents
    c3 = 2
    For c2 = 2 To 10
    
    For c1 = c2 + 1 To 10
        If ((Cells(c2, 2) - Cells(c1, 2)) ^ 2 + (Cells(c2, 3) - Cells(c1, 3)) ^ 2) = 1 Then
            If Abs(Cells(c1, 4) - Cells(c2, 4)) = 10 Then
                    Cells(c3, 8) = Cells(c1, 2)
                    Cells(c3, 9) = Cells(c1, 3)
                    Cells(c3, 10) = Cells(c2, 2)
                    Cells(c3, 11) = Cells(c2, 3)
                    c3 = c3 + 1
            End If
        End If
    Next c1
    
    Next c2
    
    End Sub