【发布时间】:2010-10-16 13:27:17
【问题描述】:
线性搜索和二分搜索有什么区别?
【问题讨论】:
-
请阅读您的课程材料中的相应部分,希望这些部分是由您的教师选择和准备的。如果做不到这一点,一般的维基百科、c2 或谷歌搜索可以回答这些问题。网上也有大量做得好的课程/讲义。
标签: algorithm search binary-search linear-search
线性搜索和二分搜索有什么区别?
【问题讨论】:
标签: algorithm search binary-search linear-search
linear search 向下查看列表,一次一个项目,没有跳跃。在复杂性方面,这是一个O(n) 搜索 - 搜索列表所花费的时间以与列表相同的速度变大。
binary search 是当您从排序列表的中间开始时,查看它是否大于或小于您要查找的值,这决定了该值是在排序列表的前半部分还是后半部分列表。跳到子列表的一半,然后再次比较等等。这几乎是人类通常在字典中查找单词的方式(尽管我们使用更好的启发式,显然 - 如果你正在寻找“猫”,你不会从“M”开始)。就复杂性而言,这是一个 O(log n) 搜索 - 搜索操作的数量比列表增长得更慢,因为每次操作都会将“搜索空间”减半。
例如,假设您在 A-Z 字母列表中查找 U(索引 0-25;我们正在查找索引 20 处的值)。
线性搜索会问:
list[0] == 'U'?没有。list[1] == 'U'?没有。list[2] == 'U'?没有。list[3] == 'U'?没有。list[4] == 'U'?没有。list[5] == 'U'?没有。
...list[20] == 'U'?是的。完成了。
二分查找会问:
比较
list[12]('M')和'U':更小,看更远。 (范围=13-25)
比较list[19]('T') 和 'U':更小,看得更远。 (范围=20-25)
比较list[22]('W') 和'U':更大,看早些。 (范围=20-21)
比较list[20]('U') 和 'U':找到了!完成。
比较两者:
【讨论】:
将其视为在电话簿中查找方式的两种不同方式。线性搜索从头开始,读取每个名称,直到找到所需内容。另一方面,二分搜索是当您打开书本(通常在中间),查看页面顶部的名称,然后确定您要查找的名称是大于还是小于您要查找的名称'正在寻找。如果您要查找的名称更大,那么您将继续以这种方式搜索书的上半部分。
【讨论】:
线性搜索的工作原理是查看数据列表中的每个元素,直到找到目标或到达末尾。这导致在给定列表上的 O(n) 性能。 二进制搜索具有必须对数据进行排序的先决条件。我们可以利用这些信息来减少我们需要查看的项目数量以找到我们的目标。我们知道,如果我们查看数据中的一个随机项目(假设是中间项目)并且该项目大于我们的目标,那么该项目右侧的所有项目也将大于我们的目标。这意味着我们只需要查看数据的左侧部分。基本上,每次我们搜索目标并错过,我们可以消除一半的剩余项目。这给了我们一个很好的 O(log n) 时间复杂度。
请记住,排序数据,即使使用最有效的算法,也总是比线性搜索慢(最快的排序算法是 O(n * log n))。因此,您永远不应该仅仅为了稍后执行单个二进制搜索而对数据进行排序。但是,如果您将执行许多搜索(例如至少 O(log n) 次搜索),则可能值得对数据进行排序,以便您可以执行二进制搜索。在这种情况下,您还可以考虑其他数据结构,例如哈希表。
【讨论】:
线性搜索从值列表的开头开始,并按顺序逐一检查您要查找的结果。
二分查找从已排序数组的中间开始,并确定您要查找的值在哪一侧(如果有)。然后以相同的方式再次搜索数组的“一半”,每次将结果分成两半。
【讨论】:
请务必仔细考虑更快的二进制搜索的胜利是否值得保持列表排序的成本(以便能够使用二进制搜索)。 IE。如果您有很多插入/删除操作并且只是偶尔进行搜索,那么二进制搜索总体上可能比线性搜索慢。
【讨论】:
试试这个:选择一个随机的名字“姓氏,名字”,然后在你的电话簿中查找。
第一次:从书的开头开始,读名字直到找到它,否则按字母顺序找到它出现的地方并注意它不在那里。
第二次:在中途点打开书,看页面。问问自己,这个人应该在左边还是右边。无论是哪一个,取那个 1/2 并找到它的中间。重复此过程,直到找到条目所在的页面,然后将相同的过程应用于列,或者像以前一样沿页面上的名称线性搜索。
为这两种方法计时并报告!
[如果你只有一个名字列表,而不是排序的话,还要考虑哪种方法更好......]
【讨论】:
线性搜索也称为顺序搜索,从头开始按顺序查看每个元素,以查看所需元素是否存在于数据结构中。当数据量较小时,这种搜索速度很快。它很容易,但所需的工作与要搜索的数据量成正比。如果所需元素不存在,则将元素数量加倍将使搜索时间加倍。
二分查找对于较大的数组是有效的。在此我们检查中间元素。如果该值大于我们要查找的值,则查看前半部分;否则,查看后半部分。重复此操作,直到找到所需的项目。必须对表进行排序以进行二分查找。它在每次迭代时消除了一半的数据。它是对数的。
如果我们要搜索 1000 个元素,二分搜索大约需要 10 步,线性搜索需要 1000 步。
【讨论】:
二分查找的运行时间为 O(logn),而线性查找的运行时间为 O(n),因此二分查找的性能更好
【讨论】:
线性搜索查找一个列表,一次一个项目,不跳转。在复杂性方面,这是一个 O(n) 搜索 - 搜索列表所花费的时间以与列表相同的速度变大。
二分查找是从已排序列表的中间开始,查看它是否大于或小于您要查找的值,这决定了该值是在列表的前半部分还是后半部分.跳到子列表的一半,然后再次比较等等。这几乎是人类通常在字典中查找单词的方式(尽管我们使用更好的启发式,显然 - 如果你正在寻找“猫”,你不会从“M”开始)。就复杂性而言,这是一个 O(log n) 搜索 - 搜索操作的数量比列表增长得更慢,因为每次操作都将“搜索空间”减半。
【讨论】:
Linear Search 浏览项目,直到找到搜索到的值。
效率:O(n)
示例 Python 代码:
test_list = [1, 3, 9, 11, 15, 19, 29]
test_val1 = 25
test_val2 = 15
def linear_search(input_array, search_value):
index = 0
while (index < len(input_array)) and (input_array[index] < search_value):
index += 1
if index >= len(input_array) or input_array[index] != search_value:
return -1
return index
print linear_search(test_list, test_val1)
print linear_search(test_list, test_val2)
Binary Search 查找数组的中间元素。检查中间值是否大于或小于搜索值。如果它更小,它会获取数组的左侧并找到该部分的中间元素。如果它更大,则获取数组的正确部分。它循环操作,直到找到搜索到的值。或者如果数组中没有值则结束搜索。
效率:O(logn)
示例 Python 代码:
test_list = [1, 3, 9, 11, 15, 19, 29]
test_val1 = 25
test_val2 = 15
def binary_search(input_array, value):
low = 0
high = len(input_array) - 1
while low <= high:
mid = (low + high) / 2
if input_array[mid] == value:
return mid
elif input_array[mid] < value:
low = mid + 1
else:
high = mid - 1
return -1
print binary_search(test_list, test_val1)
print binary_search(test_list, test_val2)
您还可以在此处查看有关线性和二进制搜索的可视化信息:https://www.cs.usfca.edu/~galles/visualization/Search.html
【讨论】:
为了清楚了解,请看一下我的codepen实现https://codepen.io/serdarsenay/pen/XELWqN
最大的区别是在应用二分搜索之前需要对样本进行排序,因此对于大多数“正常大小”(有争议的)样本,使用线性搜索算法搜索会更快。
这里是javascript代码,html和css以及完整的运行示例请参考上面的codepen链接。
var unsortedhaystack = [];
var haystack = [];
function init() {
unsortedhaystack = document.getElementById("haystack").value.split(' ');
}
function sortHaystack() {
var t = timer('sort benchmark');
haystack = unsortedhaystack.sort();
t.stop();
}
var timer = function(name) {
var start = new Date();
return {
stop: function() {
var end = new Date();
var time = end.getTime() - start.getTime();
console.log('Timer:', name, 'finished in', time, 'ms');
}
}
};
function lineerSearch() {
init();
var t = timer('lineerSearch benchmark');
var input = this.event.target.value;
for(var i = 0;i<unsortedhaystack.length - 1;i++) {
if (unsortedhaystack[i] === input) {
document.getElementById('result').innerHTML = 'result is... "' + unsortedhaystack[i] + '", on index: ' + i + ' of the unsorted array. Found' + ' within ' + i + ' iterations';
console.log(document.getElementById('result').innerHTML);
t.stop();
return unsortedhaystack[i];
}
}
}
function binarySearch () {
init();
sortHaystack();
var t = timer('binarySearch benchmark');
var firstIndex = 0;
var lastIndex = haystack.length-1;
var input = this.event.target.value;
//currently point in the half of the array
var currentIndex = (haystack.length-1)/2 | 0;
var iterations = 0;
while (firstIndex <= lastIndex) {
currentIndex = (firstIndex + lastIndex)/2 | 0;
iterations++;
if (haystack[currentIndex] < input) {
firstIndex = currentIndex + 1;
//console.log(currentIndex + " added, fI:"+firstIndex+", lI: "+lastIndex);
} else if (haystack[currentIndex] > input) {
lastIndex = currentIndex - 1;
//console.log(currentIndex + " substracted, fI:"+firstIndex+", lI: "+lastIndex);
} else {
document.getElementById('result').innerHTML = 'result is... "' + haystack[currentIndex] + '", on index: ' + currentIndex + ' of the sorted array. Found' + ' within ' + iterations + ' iterations';
console.log(document.getElementById('result').innerHTML);
t.stop();
return true;
}
}
}
【讨论】: