在JavaScript中使用容差实现二进制搜索?

时间:2016-02-08 18:29:27

标签: javascript math while-loop binary-search

我正在尝试在minmax之间找到一个数字。我只知道(通过使用more方法)我猜的数字是高于还是低于传递的数字。我需要找到的数字可以是小数,这让我感到紧张,因为平均二进制搜索似乎主要关注整数业务。

我编写的算法是尝试二进制搜索,没有数组。正如我所看到的,在经典二进制搜索之间的区别在于,搜索的值和索引已经被混合到同一个任务中。

var tolerance = 0;

var tries, min, max, current, needed;

function search () {

  tries = 0;
  min = 0;
  max = 100;
  needed = Math.random() * max;
  current = (max - min) / 2;

  while (!accept() && tries < 100) {

    if (more(current))
      min = current;
    else
      max = current;

    current = min + ((max - min) / 2);

    tries++;

  }

  results();

}

function more (n) {

  return n < needed;

}

function accept () {

  return Math.abs(current-needed) <= tolerance;

}

function results () {

  document.getElementById('results').innerHTML = 'accepted: ' + current + '<br>needed: ' + needed + '<br>tries: ' + tries;

}
<button onclick="javascript:search();">search</button>
<br>
<div id="results"></div>

我的问题是这个;鉴于我想做什么,这段代码可以改进吗?或者也许有更好的方法一起完成这一切?显然,通过增加公差来大大提高尝试次数 - 但这会以最终结果的准确性为代价。例如,在经过一定次数的尝试后增加公差是否合理?

此外,如何最好地确保所需数量在范围内?我知道在尝试!more(max) && more(min)循环之前我可以确保while,但是有一种更简单的方法,而不是简单地在脚本的开头用螺栓连接两个额外的检查吗?

2 个答案:

答案 0 :(得分:0)

搜索范围内的数字比搜索二进制搜索更难。

假设范围总是知道/类似,可以在search()函数之前使用more()函数或clamp函数进行验证。请参阅此链接clamp number

如果范围可以发生显着变化,可以使用某种指数函数来找到“良好范围”。

  • 范围0-100
  • 范围101至1000
  • 范围1001至20000

您还可以考虑将容差设置为百分比,或者设置为“好小数”。 See here

知道在搜索带有x小数的数字(即0到1000范围内的123.45)和0到100 000范围内搜索12345时,您将获得相同的效率。

由于“最坏情况”尝试次数为⌈log2(n + 1)⌉。有100次尝试允许您精确地找到0到n = 1267650600228229401496703205375范围内的数字。由于您有小数,对于您想要的每个小数精度,您需要将此数字除以10.

0.xxxxxx精度会给你一个0到12676506002282294014967032的范围,你可以在不到100次尝试中找到你的号码。

如果我的计算是正确的..

答案 1 :(得分:0)

当在实际间隔上进行二进制搜索时,不需要检查是否相等,而是继续优化搜索间隔,直到它足够小。

// Generated by CoffeeScript 1.10.0
(function() {
  var eps, hi, lo, mid, more, secret;

  // This is your tolerance value.
  eps = 0.01;

  // The binary search routine will never get to see this.
  secret = 45.63;

  more = function(test) {
    return test > secret;
  };

  lo = 0;

  hi = 100;

  while (hi - lo > eps) {
    mid = lo + ((hi - lo) / 2);
    if (more(mid)) {
      hi = mid;
    } else {
      lo = mid;
    }
  }

  console.log(mid);

}).call(this);

输出:45.635986328125

超出范围值时,输出将等于lohi,其中相等意味着它们的绝对差值将小于eps

另请参阅:Binary searching on real numbers: Topcoder

binary_search(lo, hi, p):
   while we choose not to terminate:
      mid = lo + (hi-lo)/2
      if p(mid) == true:
         hi = mid
      else:
         lo = mid

     return lo // lo is close to the border between no and yes
     

由于实数集是密集的,应该很清楚我们通常无法找到确切的目标值。但是,我们可以快速找到一些x,使得f(x)在no和yes之间的边界的某个容差范围内。我们有两种方法来决定何时终止:当搜索空间小于某个预定界限(比如10 ^ -12)时终止,或者执行固定数量的迭代。