在排序数组中进行线性搜索,增量为2而不是1

时间:2017-08-17 08:51:13

标签: javascript arrays algorithm sorting

我有一项任务是使用适用于已排序数组的线性搜索来实现contains函数。我是这样做的:

function contains(a, e) {
  for (let i = 0; i < a.length; i++) {   
    if (e === a[i]) {
      return true;
    } else if (e < a[i]) {
      return false;
    }
  }
  return false;
}

然而,对于任务,有一个注释:

  

我们可以通过更快地递增索引来进一步改进   率(比如2)。这将减少比较次数   在排序列表中搜索。

我不明白我们怎么能这样做,因为我们不能跳过元素。我唯一想到的是检查当前索引和以前的索引:

if (e === a[i] || e === a[i-1]) {

但这可能不是作者的意思。有什么想法吗?

该示例使用JavaScript语言。但是我对不特定于任何语言的通用解决方案感兴趣,因此您可以将其视为伪代码。

3 个答案:

答案 0 :(得分:3)

正如所建议的那样,我将添加自己的答案,其中包含与之前的答案相同的想法。

假设问题是使用线性搜索在key中找到array,即从i0的{​​{1}}的for循环。通常,可以通过评估每个array.length-1的{​​{1}}来做到这一点。但是,可以通过使用不等式而不是相等来跳过搜索中的每个第二个元素。 诀窍是评估array[i] == key而不是i。如果此条件为假,则认为如果键位于数组中,则它位于array[i] < keyarray[i] == key位置。

此外,可能必须显式检查数组的最后一个元素,具体取决于数组长度是偶数还是奇数。

下面提供了可运行且经过测试的代码。

array[i-1]

类似地,这个想法可以概括为跳过两个,三个...... array[i]元素。然后应该将function contains(array, key) { var i; for (i = 0; i < array.length; i += 2) { if (array[i] < key) { // continue search continue; } // compare with the current element if (array[i] === key) { return true; } // compare with the skipped element if (i > 0 && array[i - 1] === key) { return true; } // it's neither the current nor the skipped element return false; } // for even-sized arrays, check the last element if (i < array.length + 1) { if (array[i - 1] === key) { return true; } } return false; } console.log(contains([10, 20, 30, 40], 10)); // true console.log(contains([10, 20, 30, 40], 20)); // true console.log(contains([10, 20, 30, 40], 30)); // true console.log(contains([10, 20, 30, 40], 40)); // true console.log(contains([10, 20, 30, 40], 25)); // false显式检查相等性添加到循环的bpdy中。尽管如此,对于足够大的数组,二进制搜索总是会更好,因为二进制搜索会进行 O(log n)比较,而上述所有方法都进行 O(n)比较:跳过一些元素可以通过常数因子改善性能,但不是渐近。

答案 1 :(得分:1)

function contains(a, e) {
  for (let i = 0; i < a.length; i+= 2) {   
    if (e === a[i]) {
      return true;
    } else if (e < a[i]) 
    {
      //now compare with skipped element
       if(e == a[i-1]) return true; 
       else return false;
    }
  }
  return false;
}

答案 2 :(得分:0)

如果你的数组包含数字,你可以跳过每一个元素,如果你不检查元素是否相等,但是如果你检查你搜索的元素是否大于你当前索引的元素。

在每个循环中,您都会检查if array[i] < a。如果它小于a,则继续,否则您将取i-1处的值并检查这是否是您要查找的值。因为数组已排序,所以此时您知道搜索值的唯一位置是i-1

例如:

Array: [1, 2, 4, 5, 7, 10]
a: 5

array[0] < 5 -> true
array[2] < 5 -> true
array[4] < 5 -> false

此时你知道如果你的值存在于数组中,它就在array [2]和array [4]之间,因为我们知道array[2] < 5 < array[4]

现在你检查:

array[3] == 5

如果返回true,则表示数组包含值,否则不包含

function contains2(a, e) {
  for (let i = 0; i < a.length; i += 2) {
    if (a[i] < e) {
      continue;
    } else {
      if (a[i-1] === e) {
        return true;
     } else if (a[i] === e) {
       return true;
     } else {
       return false;
     }
    }
  }
  return false;
}

这是实施。在下面链接的JSBin中,您可以看到两个函数的比较。我添加了一个日志来计算每个循环的运行频率。在给定的示例中,您的函数需要运行8次,因为它会将搜索值与值array[0], array[1], array[2], array[3], array[4], array[5], array[6], array[7]进行比较,直到它给出结果。 第二个函数会跳过每隔一个条目,因此它只是将搜索值与array[0], array[2], array[4], array[6], array[8]进行比较,然后在array[7]找到它。这就是为什么它需要较少的比较。

https://jsbin.com/vojahoyaju/edit?js,console