【问题标题】:Binary search not run?二进制搜索不运行?
【发布时间】:2018-02-05 13:21:00
【问题描述】:

我尝试在我的代码示例中使用二进制搜索算法,但它没有按我的预期运行。我不知道为什么。请帮我解释一下

var array = [1, 4, 6, 8, 9, 12, 15, 17, 19, 34, 55, 78, 80];

function binarySearch (array, numberToSearch) {
var firstIndex = 0;
var lastIndex = array.length - 1;
var currentIndex;
var currentElement;

currentIndex = (lastIndex + firstIndex) / 2 | 2;
currentElement = array[currentIndex];

while (firstIndex <= lastIndex) {
    if (numberToSearch === currentElement) {
        // found
        console.log(currentIndex);
        return currentIndex;
    } else if (numberToSearch < currentElement) {
        lastIndex = currentIndex - 1;
        currentIndex = (lastIndex + firstIndex) / 2 | 2;
        currentElement = array[currentIndex];
    } else if (numberToSearch > currentElement) {
        firstIndex = currentIndex + 1;
        currentIndex = (lastIndex + firstIndex) / 2 | 2;
        currentElement = array[currentIndex];
    }
}
 return -1;
}
binarySearch(array, 12);

我应该打印:5 但什么也没发生

【问题讨论】:

  • 我猜,你的意思是二进制搜索而不是二进制排序?
  • 我认为您不允许循环使用返回 -1 完全运行。我认为您将迭代解决方案与递归解决方案混为一谈。
  • @82Tuskers 对于无结果条件,我返回 -1。但我认为这不是问题
  • return -1 不是唯一的问题,而是while 循环只进行一次迭代的原因。
  • @Thijs 好的,我认出了它,我尝试将其删除或将其置于 while 循环之外。但是代码仍然得到相同的结果:什么都没有

标签: javascript arrays algorithm search data-structures


【解决方案1】:

你的代码有什么问题:

  1. 应该是var currentIndex = (lastIndex + firstIndex) / 2 | 0; (不是| 2);

  2. currentIndexcurrentElement 应该在每个 循环内的迭代。

所以,这是您的代码的更正版本:

var array = [1, 4, 6, 8, 9, 12, 15, 17, 19, 34, 55, 78, 80];

function binarySearch (array, numberToSearch) {
var firstIndex = 0;
var lastIndex = array.length - 1;

while (firstIndex <= lastIndex) {
    var currentIndex = (lastIndex + firstIndex) / 2 | 0;
    var currentElement = array[currentIndex];
    if (numberToSearch === currentElement) {
        return currentIndex;
    } else if (numberToSearch < currentElement) {
        lastIndex = currentIndex - 1;
    } else if (numberToSearch > currentElement) {
        firstIndex = currentIndex + 1;
    }
}
 return -1;
}

console.log(binarySearch(array, 99)); // -1
console.log(binarySearch(array, 12)); // 5

顺便说一句,这个var currentIndex = (lastIndex + firstIndex) / 2 | 0; 看起来很不寻常。常用方式为var currentIndex = Math.floor((lastIndex + firstIndex) / 2);

【讨论】:

  • 虽然var currentIndex = (lastIndex + firstIndex) / 2 | 0;对你来说似乎很陌生,但它是most optimal。你不应该阻止良好的做法。
  • 我相信你是对的,但它在 JS 的这种情况下并不常用——我的意思是它不是每个人都知道和理解的东西,优化本身几乎是不可察觉的。所以,我更喜欢用更清晰的东西。
  • 顺便说一句,有一次我看过 Douglas Crockford 的视频,他警告来自 C++ 等的人在 JS 位运算符有不同的成本,他不建议使用它们,除非它们是你实际的想要表演。
【解决方案2】:

这是我更新的所有地方的正确答案。你非常接近!似乎您正在将二进制搜索的iterative 版本与recursive 解决方案结合起来。

CodePen Demo

var array = [1, 4, 6, 8, 9, 12, 15, 17, 19, 34, 55, 78, 80];

function binarySearch (array, numberToSearch) {
  var firstIndex = 0;
  var lastIndex = array.length - 1;
  var currentIndex;
  var currentElement;

  while (firstIndex <= lastIndex) {
    currentIndex = (lastIndex + firstIndex) / 2 | 0; //should default to zero, not Two! 
    currentElement = array[currentIndex];//These should both update every iteration so it does not infinitely loop!
    if (numberToSearch === currentElement) {
      // found
      console.log(currentIndex);
      return currentIndex;
    }else if (numberToSearch < currentElement) {
      lastIndex = currentIndex - 1; //If current is too big, move right pointer to the left
    }else if (numberToSearch > currentElement) {
      firstIndex = currentIndex + 1;//If current is too small, move left pointer to the right
    }
  }
  return -1;//When condition of while it broken and no solution has been found, return -1 to indicate it is not in the array
}
binarySearch(array, 12) //5

进一步优化了 Math.floor() 作为 number | 0 is sometimes faster.

【讨论】:

  • 非常干净!感谢您花时间解决我的问题 :)
【解决方案3】:

首先,这里的按位OR 有什么意义:

currentIndex = (lastIndex + firstIndex) / 2 | 2;

我认为应该是:

currentIndex = (lastIndex + firstIndex) / 2;

搜索空间更新存在基本的缺陷。 当numberToSearch &lt; currentElement 表示middle element(当前索引处的元素) 大于要搜索的数字时,因此,正确的新边界是

lastIndex = currentIndex - 1;

另外,当numberToSearch &gt; currentElement 表示middle element(当前索引处的元素) 小于要搜索的数字时,因此,正确的新边界是: p>

firstIndex = currentIndex + 1;

因此,正确的代码是:

var array = [1, 4, 6, 8, 9, 12, 15, 17, 19, 34, 55, 78, 80];

function binarySearch (array, numberToSearch) {
var firstIndex = 0;
var lastIndex = array.length - 1;
var currentIndex;
var currentElement;

currentIndex = (lastIndex + firstIndex) / 2;
currentElement = array[currentIndex];

while (firstIndex <= lastIndex) {
    if (numberToSearch === currentElement) {
        // found
        console.log(currentIndex);
        return currentIndex;
    } else if (numberToSearch < currentElement) {
        lastIndex = currentIndex - 1;
        currentIndex = (lastIndex + firstIndex) / 2 | 2;
        currentElement = array[currentIndex];
    } else if (numberToSearch > currentElement) {
        firstIndex = currentIndex + 1;
        currentIndex = (lastIndex + firstIndex) / 2 | 2;
        currentElement = array[currentIndex];
    }
}
 return -1;
}
binarySearch(array, 12);

【讨论】:

  • 哦,我在逻辑代码中看到了我的错误:)。我编辑了它,但你知道,仍然没有得到结果。您可以尝试在您的计算机上运行此代码。逻辑是正确的。
  • 他最初没有使用Math.floor()是正确的。他使用的方法is sometimes faster,但应该是0,而不是2。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-10
  • 2014-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多