JavaScript - 二进制搜索每次都会挂起

时间:2016-02-04 05:55:00

标签: javascript arrays binary-search

我有一个2D数组,如下所示:

[1.11, 23]
[2.22, 52]
[3.33, 61]
...

数组按每行的第一个值排序。

我试图在数组中找到一个 close 到搜索值的值 - 在一定的灵敏度范围内。设置方式和灵敏度值确保数组中只有一个匹配。

搜索值是鼠标的当前x-pos。搜索在mousemove上调用,因此经常被调用。

最初我有以下内容(使用开始到结束for循环):

for(var i = 0; i < arr.length; i++){
    if(Math.abs(arr[i][0] - x) <= sensitivity){
        hit = true;
        break;
    }
}

它就像一个魅力。到目前为止,我只使用小数据集,所以使用这种方法没有明显的滞后。但是,最终我将使用更大的数据集,因此希望将其切换为二进制搜索

var a = 0;
var b = arr.length - 1;
var c = 0;

while(a < b){
    c = Math.floor((a + b) / 2);

    if(Math.abs(arr[c][0] - x) <= sensitivity){
        hit = true;
        break;
    }else if(arr[c][0] < x){
        a = c;
    }else{
        b = c;
    }
}

这种方法运行良好,持续2秒,然后它会挂起到需要重新启动浏览器的位置。我过去常常使用二进制搜索,并且在我的生活中无法弄清楚为什么这个搜索工作不正常。

编辑1

var sensitivity = (width / arr.length) / 2.001

数组中的点是等距的,因此这种灵敏度可确保两个arr值之间没有模糊的1/2路点。你或者是其中一个。

值是在页面加载时动态创建的,但看起来与我上面提到的完全一样。 x值具有更显着的数字,y值遍布整个地方,但我提供的小样本与生成的样本之间没有显着差异。

编辑2

打印了一个动态创建的列表:

[111.19999999999999, 358.8733333333333]
[131.4181818181818, 408.01333333333326]
[151.63636363636363, 249.25333333333327]
[171.85454545454544, 261.01333333333326]
[192.07272727272726, 298.39333333333326]
[212.29090909090908, 254.2933333333333]
[232.5090909090909, 308.47333333333324]
[252.72727272727272, 331.1533333333333]
[272.94545454545454, 386.1733333333333]
[293.16363636363633, 384.9133333333333]
[313.3818181818182, 224.05333333333328]
[333.6, 284.53333333333325]
[353.81818181818187, 278.2333333333333]
[374.0363636363637, 391.63333333333327]
[394.25454545454556, 322.33333333333326]
[414.4727272727274, 300.9133333333333]
[434.69090909090926, 452.95333333333326]
[454.9090909090911, 327.7933333333333]
[475.12727272727295, 394.9933333333332]
[495.3454545454548, 451.27333333333326]
[515.5636363636366, 350.89333333333326]
[535.7818181818185, 308.47333333333324]
[556.0000000000003, 395.83333333333326]
[576.2181818181822, 341.23333333333323]
[596.436363636364, 371.47333333333324]
[616.6545454545459, 436.9933333333333]
[636.8727272727277, 280.7533333333333]
[657.0909090909096, 395.4133333333333]
[677.3090909090914, 433.21333333333325]
[697.5272727272733, 355.09333333333325]
[717.7454545454551, 333.2533333333333]
[737.963636363637, 255.55333333333328]
[758.1818181818188, 204.7333333333333]
[778.4000000000007, 199.69333333333327]
[798.6181818181825, 202.63333333333327]
[818.8363636363644, 253.87333333333328]
[839.0545454545462, 410.5333333333333]
[859.272727272728, 345.85333333333324]
[879.4909090909099, 305.11333333333323]
[899.7090909090917, 337.8733333333333]
[919.9272727272736, 351.3133333333333]
[940.1454545454554, 324.01333333333326]
[960.3636363636373, 331.57333333333327]
[980.5818181818191, 447.4933333333333]
[1000.800000000001, 432.3733333333333]

如您所见,它按每行中的第一个值(按升序排序)排序。

将条件更改为

while(a < b)

var b = positions.length;

else if(arr[c][0] < x){
    a = c + 1;
}

做了这个伎俩。

2 个答案:

答案 0 :(得分:3)

您的二进制搜索似乎有点偏离:试试这个。

var arr = [[1,0],[3,0],[5,0]];

var lo = 0;
var hi = arr.length;

var x = 5;
var sensitivity = 0.1;

while (lo < hi) {
    var c = Math.floor((lo + hi) / 2);
    if (Math.abs(arr[c][0] - x) <= sensitivity) {
        hit = true;
        console.log("FOUND " + c);
        break;
    } else if (x > arr[c][0]) {
        lo = c + 1;
    } else {
        hi = c;
    }
}

这是对任何实现二进制搜索的人的一般参考。

让:

  • lo是可能包含您的值的最小索引,
  • hi 一个,而不是可能包含您的值的最大索引

如果遵循这些约定,那么二进制搜索就是:

while (lo < hi) {
    var mid = (lo + hi) / 2;

    if (query == ary[mid]) {
        // do stuff

    else if (query < ary[mid]) {

        // query is smaller than mid
        // so query can be anywhere between lo and (mid - 1)
        // the upper bound should be adjusted

        hi = mid;
     else {

        // query can be anywhere between (mid + 1) and hi.
        // adjust the lower bound

        lo = mid + 1;
}

答案 1 :(得分:2)

我不知道您的确切情况,但这是代码崩溃的方式:

1)从具有两个X值的数组开始。该数组的长度为2,因此a = 0,b = 1,c = 0。

2)a&lt; b,所以while循环执行。

3)c = floor((a + b)/ 2)= floor(0.5)= 0.

4)假设鼠标不在第一个X值的灵敏度范围内,所以第一个if分支没有命中。

5)假设我们的X值在我们鼠标的右边,所以第二个if分支进入。这设置了a = c或0,它已经是。

6)因此,我们得到了无限循环。