我正在使用C#,我有两个list<AACoordinate>
,其中这些列表中的每个元素用x,y和z表示空间中的3D点。
class AACoordinate
{
public int ResiNumber { get; set; }
public double x { get; set; }
public double y { get; set; }
public double z { get; set; }
}
每个列表可以包含2000个或更多点,我的目的是将list1的每个点与list2的所有点进行比较,如果距离小于特定的数字,我会记录它。目前我正在使用 foreach 将list1的每个元素与list2的所有元素进行比较。由于点数的原因,这很慢。你有任何建议让它快速吗?
我的循环是:
foreach (var resiSet in Program.atomList1)
{
foreach (var res in Program.atomList2)
{
var dis = EuclideanDistance(resiSet, res);
if (dis < 5)
temp1.Add(resiSet.ResiNumber);
}
}
提前感谢您的帮助。
答案 0 :(得分:1)
实施起来可能有点复杂,但除此之外我没有任何其他想法:
要降低计算复杂度,可能需要使用一些数据结构,如KD-Tree或QuadTree。
您可以使用KD-Tree进行最近邻搜索,这就是您所需要的。
1)为O(n log n)中的第一个列表构建kd-tree。这必须在一个线程中完成。
2)对于第二个列表中的每个项目,您在kd树中查找最近的邻居(距您要查找的点的最近点),在O(m log n)中。如果从当前点到最近的找到点的距离小于您的增量,则可以使用它。如果您愿意,可以使用多个线程执行此步骤。
所以最后算法的复杂度将是O(max(n,m)* log n),其中n是第一个列表中的项目数,m是第二个列表中的项目数。 / p>
对于KD-Trees,请参阅:
请参阅http://home.wlu.edu/~levys/software/kd/这似乎是一个很好的实现,在java和C#中。
请参阅http://www.codeproject.com/KB/architecture/KDTree.aspx
对于四叉树,请参阅:
请参阅http://csharpquadtree.codeplex.com/
请参阅http://www.codeproject.com/KB/recipes/QuadTree.aspx
当然,在维基百科上查看什么是四叉树和kd树
考虑(2000 * log base 2(2000))约为21931.5
相反,2000 * 2000是4000000,这是一个很大的区别!
使用并行算法,如果你有4个处理器,普通的O(n * n)算法每个处理器需要1000000,我想,如果你需要快速或几乎实时的话,它仍然会太多。 / p>
答案 1 :(得分:0)
您可以使用并行库找到Parallel.ForEach。 Paralel Example
答案 2 :(得分:0)
如果你真的想要将list1的每个元素与list2中的每一个进行比较,那么你将无法摆脱嵌套for。但你可以使用Parallel.ForEach加快速度。
答案 3 :(得分:0)
您当前的方法检查L x R中的每个有序对,这是一种简单的O(n ^ 2)算法。想到了几个想法。
首先,您可以尝试将两个阵列中的每一个分成例如边长等于最大距离的立方体;那么你只需计算L和R中元素之间的距离,如果它们不超过1立方。在最坏的情况下,这仍然是O(n ^ 2),但如果你的点平均距离比你的最大距离更远,你可以在这里节省大量的虚假比较。
其次,您可以微观优化您的距离功能。例如,您永远不需要使用sqrt();将平方距离与最大距离平方进行比较就足够了。此外,如果首先检查| dx |,| dy |,则可以避免进行整数乘法来得到平方距离或| dz |满足某些属性(即,已经大于最大距离)。
其他海报提到的并行化总是一个不错的选择。特别是,复杂的并行化+装箱策略(在第一个建议中概述)应该是一个特别可扩展,高效的解决方案。