在排序数组中,返回等于或大于给定值的所有值

时间:2018-10-11 22:12:26

标签: javascript

我有一个排序数组:

[0, 1, 1, 2, 3, 4, 6, 6, 6, 50, 70, 80, 81, 100, 10000]

我正在尝试使用二进制搜索来分析此排序后的数组,并返回该数组中大于或等于给定值的所有值。因此,如果我输入搜索6,则需要的结果数组将是:

[6, 6, 6, 50, 70, 80, 81, 100, 10000]

我不能仅仅寻找一个值的第一次出现,因为该值可能不存在于数组中。例如,我可能需要寻找5,它不存在,但是我的输出将与上面的相同。

我这里有一些代码陷入了这个jsFiddle的无限循环中:http://jsfiddle.net/2mBdL/691/

var arr = [0, 1, 1, 2, 3, 4, 6, 6, 6, 50, 70, 80, 81, 100, 10000];

function binarySearch(arr, i) {
    var mid = Math.floor(arr.length / 2);
    var leftOfMid = mid - 1;
    console.log(arr[mid], i);

    if (arr[mid] == i && arr[leftOfMid] == i) {
        console.log('needle is exactly at 6, but left is same, checking lower half', arr[mid], i);
        binarySearch(arr.splice(leftOfMid, Number.MAX_VALUE), i);
    } else if (arr[mid] < i && arr.length > 1) {
        console.log('needle is at a value that is less than 6', arr[mid], i);
        binarySearch(arr.splice(mid, Number.MAX_VALUE), i);
    } else if (arr[mid] > i && arr.length > 1) {
        console.log('needle is at a value that is higher than 6 days', arr[mid], i);
        binarySearch(arr.splice(0, mid), i);
    } else if (arr[mid] == i && arr[leftOfMid] < i) {
        console.log('MATCH, needle is the beginning of the range', arr[mid], i);
        return arr[mid];
    }
    else {
        console.log('not here', i);d
        return -1;
    }

}

var result = binarySearch(arr, 6);
console.log(result);

对于该用例,我如何利用二进制搜索?数组可能会变得非常大,所以我真的想让它正常工作!

4 个答案:

答案 0 :(得分:0)

您可以简单地使用Array.prototype.filter来过滤数组中的元素。

array.filter(i => i >= 6) 

console.log(
[0, 1, 1, 2, 3, 4, 6, 6, 6, 50, 70, 80, 81, 100, 10000]
.filter(i => i >= 6) 
);

或以功能形式:

function search(arr, n) {
  return arr.filter(i => i >= n);
}

 let arr = [0, 1, 1, 2, 3, 4, 6, 6, 6, 50, 70, 80, 81, 100, 10000]
 
    
    function search(arr, n) {
     return arr.filter(i => i >= n);
    }
    
    console.log( search(arr, 6) );

答案 1 :(得分:0)

二进制搜索在这里无济于事,因为它搜索的不是范围内的单个值,因此您不知道当前迭代中测试的值是否是第一个大于6的值。解决方法非常简单:

arr.filter(e => e > i);

答案 2 :(得分:0)

可以为此使用二进制搜索。您只需要搜索值从小于目标到大于或等于目标的边界。

function bsearch(arr, lim, start = 0, end = arr.length - 1) {
  let index = Math.floor((end - start) / 2) + start
  if (start >= end) return -1
  if (arr[index] > lim)
    return (arr[index - 1] < lim || arr[index - 1] === undefined) ? index : bsearch(arr, lim, start, index)
  if (arr[index] < lim)
    return arr[index - 1] > lim ? index : bsearch(arr, lim, index + 1, end)
  if (arr[index] === lim) {
    return (arr[index - 1] === lim) ? bsearch(arr, lim, start, index) : index
  }
}

let arr = [0, 1, 1, 2, 3, 4, 6, 6, 6, 50, 70, 80, 81, 100, 10000]
// all values >= 6
let index = bsearch(arr, 6)
console.log(arr.slice(index))

// all values >=  5
index = bsearch(arr, 5)
console.log(arr.slice(index))

在大型数组上,这将具有二进制搜索的所有优点。例如,搜索10000个元素的数组仅需进行13次迭代。

答案 3 :(得分:0)

二进制搜索确实可以帮助大型数组,对于较小的数组则可能无关紧要。我认为您的策略还可以,但是实施过程似乎有些复杂,所以我看不到您的错误在哪里。

考虑以下内容,我尝试通过添加注释使其简单:

var arr = [0, 1, 1, 2, 3, 4, 6, 6, 6, 50, 70, 80, 81, 100, 10000];

function binaryFind(arr, value) {
  
  // Helper: go down until stop getting matches
  function goLeft(arr, value, pos) {
    while (arr[pos - 1] == value) --pos;
    return arr.slice(pos);
  }
  
  // Find match or first value larger
  function search(arr, value, pos, iteration, direction) {
  
    // Update position for this iteration
    ++iteration;
    pos += direction * arr.length / (iteration*2) | 0;

// Check if at start or end of array
    if (pos >= arr.length) {
      return [];
    } else if (pos <=0) {
      return arr.slice(0);
    }    
    // Hit value
    if (arr[pos] == value) {
      return goLeft(arr, value, pos);
    }
    
    // Under
    if (arr[pos] < value) {
      // Check higher adjacent
      if (arr[pos + 1] >= value) {
        return arr.slice(pos+1);
      }
      //Otherwise search up
      return search(arr, value, pos, iteration, 1);
    }
    
    // Over
    if (arr[pos] > value) {
      // Check lower adjacent
      if (arr[pos - 1] < value) {
        return arr.slice(pos);
      }
      // Otherwise search down
      return search(arr, value, pos, iteration, -1);
    }
  }
  return  search(arr, value, 0, 0, 1);
}

[0,1,2,3,4,5,6,7,55,1e6,555,70,69,-1,71].forEach(v =>
  console.log(v + ': ' + binaryFind(arr, v))
);

马克·迈耶(Mark Meyer)搜索边界的想法让我开始思考,所以这是一个应该更有效的版本,因为它继续使用二进制搜索,而不是“向下”查找匹配值(它寻找第一个值是)。当然,使用真实数据进行测试将确定这是否有好处,但这是一个更简单的解决方案。

将搜索功能包装在外部功能中,以防止滥用其他参数。没有包装程序,它只有3行代码,但其中的一行有点长。 ;-)

// Use a binary search to find all elements in a sorted array
// that are equal to or greater than value.
function binaryFind(arr, value) {
  function search(arr, value, pos=0, iteration=1, direction=1) {
    pos += direction * arr.length / (iteration*2) | 0;
    return pos >= arr.length? [] :
           pos <=0? arr.slice(0) :
           arr[pos] < value? (arr[pos + 1] >= value? arr.slice(pos+1) : search(arr, value, pos, ++iteration,  1)):
                             (arr[pos - 1] <  value? arr.slice(pos)   : search(arr, value, pos, ++iteration, -1));
  }
  return  search(arr, value);
}

// Testing
var arr = [0, 1, 1, 2, 3, 4, 6, 6, 6, 50, 70, 80, 81, 100, 10000];
[0,1,2,3,4,5,6,7,55,1e6,555,70,69,-1,71].forEach(v =>
  console.log(v + ': ' + binaryFind(arr, v))
);