如何有效地检查列表项与所有其他列表项?

时间:2012-12-11 00:16:56

标签: javascript optimization

有没有办法优化这种搜索方法?

for (var i=0;i<dots.length;i++) {
        var blist = [];
        for (var n=0;n<dots.length;n++) {
            if (dots[n][1]>(dots[i][1]-90) 
            && dots[n][1]<(dots[i][1]+90) 
            && dots[n][2]>(dots[i][2]-90) 
            && dots[n][2]<(dots[i][2]+90)) {
                if (!(n === i)) blist.push(n);
            }
        }

dots[x][1]是x坐标,dots[x][2]是y坐标。

我有1000个点,需要找到每个点周围的点,以便产生

if (dots[n][1]>(dots[i][1]-90) 
&& dots[n][1]<(dots[i][1]+90) 
&& dots[n][2]>(dots[i][2]-90) 
&& dots[n][2]<(dots[i][2]+90)) 

每秒运行一百万次,有没有办法对此进行优化?

3 个答案:

答案 0 :(得分:1)

也许尝试使用像这样的点数据结构

var Dot = function(){
 var x = 0;
 var y = 0;
 var Up;
 var Right;
 var Left;
 var Down;

 function init(xVal,yVal)
 {
  x = xVal;
  y = yVal;
 }

 function GetUp()
 {
  return Up;
 }

 function SetUp(UpDot)
 {
  Up = UpDot;
 }

 return 
 {
  init: init,
  GetUp: GetUp,
  SetUp: SetUp
 };
};

然后像这样使用它

var Dots = [];
var firstDot = new Dot();
Dots.push(firstDot);
var secondDot = new Dot();
secondDot.init(0,90);
secondDot.SetUp(firstDot);
Dots.push(secondDot);

显然,需要添加和配置更多以匹配您的情况。然而,这将允许你做的是迭代点,然后检查天气存在一个近点,使时间O(n)而不是O(n ^ 2),从而节省你900,000支票。

答案 1 :(得分:0)

将时间缩短一半的一种方法是不要仔细检查每一对:

for (var i = 0, len = dots.length; i < len - 1; i++) {
    var blist = [];
    for (var n = i + 1; n < len; n++) {
        if (dots[n][1]>(dots[i][1]-90) 
        && dots[n][1]<(dots[i][1]+90) 
        && dots[n][2]>(dots[i][2]-90) 
        && dots[n][2]<(dots[i][2]+90)) {
            blist.push(i);
            blist.push(n);
        }
    }
}

注意循环边界的变化。这允许我只检查每对,并跳过(n === i)检查。

我也会缓存dot.length,这可能不是什么大问题,但值得做一个紧凑的循环。

不过,这应该是超过50%的改善。虽然这可能有所帮助,但这并不是这类问题可能需要的数量级变化。

答案 2 :(得分:0)

这是一个解决方案的草图。这可能与TravisJ建议的想法相同,尽管我不清楚。它实际上只是一个草图,并将采用重要的代码来实现。

如果将空间划分为90个单位x 90个单位区域,则特定区域中的点只能足够接近该区域中的点或该区域的八个邻居之一中的点。这可以显着减少您需要比较的对数。成本当然是算法的复杂性:

  • 首先创建一个数据结构来表示您的网格部分。它们可能仅由左上角表示,因为它们的高度和宽度将固定在90,除了可能在后缘处,它可能无关紧要。假设一个矩形表面,每个可能有三个,五个或八个邻居(角落,边缘,内部部分)。
  • 循环点,确定他们居住的部分。如果你的总网格从0开始,这应该是相对简单的,使用一些Math.floor(something / 90)操作。
  • 对于每个部分,在其自身及其每个邻居上运行上面的循环以查找匹配集。您可以使用我之前的答案中缩短版本的循环。
  • 为了进一步优化,您还可以减少要检查的邻居数量。如果Section3,7与Section3,8进行比较,那么Section3,8也没有理由与Section3,7进行比较。因此,您只检查邻居的某个子集,例如那些其截面编号的x和y分量大于或等于他们自己的邻居。

我没有测试过这个,除了在我脑海里。它应该工作,但我没有尝试编写任何代码。代码不会是微不足道的。我不认为这是几个星期的工作,但也不是几分钟内鞭打在一起的东西。

我相信它可以显着提高速度,但这取决于有多少匹配,有多少个点相对于部分的数量。