我有一项任务是使用适用于已排序数组的线性搜索来实现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语言。但是我对不特定于任何语言的通用解决方案感兴趣,因此您可以将其视为伪代码。
答案 0 :(得分:3)
正如所建议的那样,我将添加自己的答案,其中包含与之前的答案相同的想法。
假设问题是使用线性搜索在key
中找到array
,即从i
到0
的{{1}}的for循环。通常,可以通过评估每个array.length-1
的{{1}}来做到这一点。但是,可以通过使用不等式而不是相等来跳过搜索中的每个第二个元素。
诀窍是评估array[i] == key
而不是i
。如果此条件为假,则认为如果键位于数组中,则它位于array[i] < key
或array[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]
找到它。这就是为什么它需要较少的比较。