我有一个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;
}
做了这个伎俩。
答案 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)因此,我们得到了无限循环。