数据结构与算法学习笔记——查找Search
顺序查找及算法分析(Sequential Search):
如果数据项保存在如列表这样的集合中,我们回陈这些数据想具有线性或者顺序关系。
例如在python list中,这些数据项的存储位置陈伟下标,这些下标都是有序的整数。 通过下标,我们就可以按照顺序来访问和查找数据项。 这些技术成为”顺序查找“
要确定列表中是否存在需要查找到数据项:
首先要从列表的第一个数据项开始,按照下标增长的顺序,逐个对比数据项,
如果到最后一个都未发现要查找的项,那么查找失败。
def sequentialSearch (alist,item): pos = 0 found = False while pos< len(alist): if alist[pos] == item: found = True else: pos += 1 return found
当输入的数组是无序(每个元素出现在每个位置的概率是相同的情况下):计算(对比)的次数也是不一样的。
但无论数组是有序的还是无序的,算法的复杂都都是不变的(O(n)),因为它们在计算的数量级上是没有变化的。
二分查找算法及分析(Binary Search):
对于有序表,如果按照顺序查找的方法,倘若第一个数据项不匹配查找想的话,那么最多还有n-1个待对比的数据项。
但是,如果从列表的中间开始比对,则会出现两种情况:
1. 列表中间项比查找项大,那么查找项只可能出现在前半部分
2. 列表中间项比查找项小,那么查找项只可能出现在后半部分
但无论如何,对比的范围都缩小到了原来的一般.
Python实现:
def binary_search(alist,item): first = 0 last = len(alist)-1 found = False while first < last and not found: midPoint = (first + last) // 2 if alist[midPoint] == item: found = True elif alist[midPoint] > item: last = midPoint -1 else: first = midPoint + 1 return found
二分法体现了一种典型策略:分而治之
即将问题分为若干个更小规模的部分,这于递归的特点也很相似。所以二分法也适用递归算法来实现:
def binary_search_recursion(alist,item): if len(alist) == 0: return False midpoint = len(alist)//2 if alist[midpoint] == item: return True else: if alist[midpoint] > item: return binary_search_recursion(alist[0:midpoint],item) elif alist[midpoint] < item: return binary_search_recursion(alist[midpoint+1:],item) print(binary_search_recursion([1,2,3,4,5],5))
由于而二分查找每次都会将下一步的比对范围缩小一半, 当对比次数足够多以后,比对范围就会仅剩余1个数据项。
即若数据项的个数为n,经过x次后可以缩小至范围为。
2^x = N => x = log2(N)
所以算法复杂度为O(log N)
还有一个因素需要注意:
binarySearch(alist[:midpoint],item) 这个递归调用使用了列表切片,而且pain操作的复杂度是O(K),这样会使得整个算法的时间复杂度稍有增加;
如果要减少这个时间开销,可以传入其实和结束的索引
另外,虽然二分查找在时间复杂度上优于顺序查找,但也要考虑到对数据项进行排序的开销。如果依次排序后就可以进行多次查找,那么排序的开销就可以摊薄。但如果数据集经常变动,查找次数相对较少,那么可能还是直接用无序表叫上顺序查找来得经济。
所以在算法的选择问题上,光看时间复杂度的优劣是不够的,还需要考虑到实际应用的情况。
浙公网安备 33010602011771号