二分查找(折半查找)
-
定义
- 二分查找又称折半查找,是一种高效率的数据查找方法。其思想是按比例逐步缩小需要考虑的数据范围,从而快速逼近需要查找的数据。该过程可以类比于我们中学时查字典的过程(假设 字典的索引被吃了),如果你要查询一个字“破”,那么思考下你要怎么查询?是不是首先需要根据“破”的拼音首字母“P”,找到在字典的大致位置(前半部分还是后半部分),显然“P”位于26个英文字母的后半部分,因此下一步就是在这后半部分中再分为两部分继续确定,此时“P”位于前半部分,以此类推,直到找到“P”的位置(例如在字典的350-430页)。然后次位的拼音“O”再按照这种方式,定位“PO”组合的位置。
-
查找过程(设顺序表元素升序排列)
-
1)初始时,考虑的元素区间是整个顺序表
-
2)取所考虑的元素范围内位置居中的那个元素(中间项),比较该元素和检索元素的关系,如果相等则检索结束,返回True
-
3) 如果检索元素大,则检索范围修改为中间项之后的半区间;如果检索元素小,则检索范围修改为中间项之前的半区间
- 4)如果区间范围内有数据就执行步骤2),否则检索元素不在顺序表中,返回False
-
实现
-
二分查找有递归实现和循环实现方式,如下:
def binary_search(search_list, search_element): """二分查找:基于递归,返回是否存在该元素""" s_len = len(search_list) if s_len > 0: mid_element = s_len // 2 # 中间元素恰好为所要查询的元素 if search_list[mid_element] == search_element: return True # 所要查询的元素位于原序列左侧 elif search_list[mid_element] > search_element: return binary_search(search_list[:mid_element], search_element) # 所要查询的元素位于原序列右侧 else: return binary_search(search_list[mid_element+1:], search_element) return False if __name__ == "__main__": L1 = [1, 3, 5, 6, 12, 23, 34, 35, 43, 55, 65] print(binary_search(L1, 43)) print(binary_search(L1, 5)) print(binary_search(L1, 11)) print(binary_search(L1, 23))
def binary_search(search_list, search_element): """二分查找:基于循环,返回是否存在该元素""" s_len = len(search_list) # 利用索引值的改变,定位在原列表的查询范围 first_idx = 0 last_idx = s_len-1 # 当前面索引小于等于后面索引,执行查找;需要注意等号也成立 while first_idx <= last_idx: mid_idx = (first_idx + last_idx) // 2 if search_list[mid_idx] == search_element: return True elif search_list[mid_idx] > search_element: last_idx = mid_idx - 1 else: first_idx = mid_idx + 1 return False if __name__ == "__main__": L1 = [1, 3, 5, 6, 12, 23, 34, 35, 43, 55, 65] print(binary_search(L1, 43)) print(binary_search(L1, 5)) print(binary_search(L1, 11)) print(binary_search(L1, 23))
-
复杂度
- 最优时间复杂度:O(1)
- 最坏时间复杂度:O(logn)
-
优缺点
- 优点:查找速度快,比较次数少,平均性能好
- 缺点:要求待查表为有序表,且插入删除困难
参考:数据结构与算法(python语言描述)裘宗燕
黑马python数据结构与算法系列课程