二分查找及其变体

  二分查找算法是针对有序数据集合的查找算法,也叫折半查找算法:每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为0二分查找的最好时间复杂度是O(1),最坏时间复杂度是O(logn),这种对数时间复杂度极其高效,有时甚至比O(1)的算法还要高效。

1.最简单的二分查找法(不含重复的元素)代码实现:

1.1.递归形式

 1 def binary_search(alist, item):
 2     """二分查找---递归版本"""
 3     n = len(alist)
 4     if n > 0:  # 递归终止条件,区间没有元素
 5         mid = n // 2  # 中间位置
 6         if alist[mid] == item:
 7             return True
 8         elif alist[mid] > item:
 9             return binary_search(alist[:mid], item)  # 在新区间内继续查找
10         else:
11             return binary_search(alist[mid+1:], item)  # 在新区间内继续查找
12     return False  # 没有查到元素

1.2.非递归形式

 1 def binary_search(alist, item):
 2     """二分查找---非递归版本"""
 3     n = len(alist)
 4     left, right = 0, n-1
 5     while left <= right:  # 查找控制
 6         mid = left + ((right - left) >> 2)  # >>的优先级比较低
 7         if alist[mid] == item:
 8             return True
 9         elif alist[mid] > item:
10             right = mid - 1
11         else:
12             left = mid + 1
13     return False

2.二分查找法的变体

2.1.查找第一个值等于给定值的元素

# 在a[mid] = item的情况下:
# 若mid=0,该元素已经是数组的第一个元素,那它肯定是我们要找的;
# 若mid!=0,但a[mid]的前一个元素a[mid-1]!=item,则a[mid]就是要找的第一个等于给定值的元素;
# 若mid!=0,且a[mid]前面的一个元素[mid-1]也等于item,则此时的a[mid]不是第一个等于给定值的元素,第一个值还在它前面;
 1 def binary_search(alist, item):
 2     """二分查找---变体"""
 3     n = len(alist)
 4     left, right = 0, n-1
 5     while left <= right:  # 查找控制
 6         mid = left + ((right - left) >> 2)  # >>的优先级比较低
 7         if alist[mid] > item:
 8             right = mid - 1
 9         elif alist[mid] < item:
10             left = mid + 1
11         else: 
12             if mid == 0 or alist[mid-1] != item:
13                 return mid
14             else:
15                 right = mid - 1
16     return False

2.2.查找最后一个值等于给定值的元素

# 在a[mid] = item的情况下:
# 若mid=n-1,该元素已经是数组的最后一个元素,那它肯定是我们要找的;
# 若mid!=0,但a[mid]的后一个元素a[mid+1]!=item,则a[mid]就是要找的最后一个等于给定值的元素;
# 若mid!=0,且a[mid]后面的一个元素a[mid+1]也等于item,则此时的a[mid]不是最后一个等于给定值的元素,最后一个值还在它后面;
 1 def binary_search(alist, item):
 2     """二分查找---变体"""
 3     n = len(alist)
 4     left, right = 0, n-1
 5     while left <= right:  # 查找控制
 6         mid = left + ((right - left) >> 2)  # >>的优先级比较低
 7         if alist[mid] > item:
 8             right = mid - 1
 9         elif alist[mid] < item:
10             left = mid + 1
11         else:
12             if mid == n-1 or alist[mid+1] != item:
13                 return mid
14             else:
15                 left = mid + 1
16     return False

2.3.查找第一个大于等于给定值的元素

# 在a[mid] >= item的情况下:
# 若mid==0,该元素已经是数组的第一个元素,那它肯定是我们要找的;
# 若mid!=0,但a[mid]的前一个元素a[mid-1] < item,则a[mid]就是要找的第一个大于等于给定值的元素;
# 若mid!=0,且a[mid]前面的一个元素[mid-1]也大于等于item,则此时的a[mid]不是第一个大于等于给定的元素,第一个值还在它前面;
 1 def binary_search(alist, item):
 2     """二分查找---变体"""
 3     n = len(alist)
 4     left, right = 0, n-1
 5     while left <= right:  # 查找控制
 6         mid = left + ((right - left) >> 2)  # >>的优先级比较低
 7         if alist[mid] >= item:
 8             if mid == 0 or alist[mid-1] < item:
 9                 return mid
10             else:
11                 right = mid - 1
12         else:
13             left = mid + 1
14     return False

2.4.查找最后一个小于等于给定值的元素

# 在a[mid] <= item的情况下:
# 若mid==n-1,该元素已经是数组的最后一个元素,那它肯定是我们要找的;
# 若mid!=0,但a[mid]的后一个元素a[mid+1] > item,则a[mid]就是要找的最后一个小于等于给定值的元素;
# 若mid!=0,且a[mid]后面的一个元素[mid+1]也小于等于item,则此时的a[mid]不是最后一个小于等于给定的元素,第一个值还在它后面;
 1 def binary_search(alist, item):
 2     """二分查找---变体"""
 3     n = len(alist)
 4     left, right = 0, n-1
 5     while left <= right:  # 查找控制
 6         mid = left + ((right - left) >> 2)  # >>的优先级比较低
 7         if alist[mid] <= item:
 8             if mid == n-1 or alist[mid+1] > item:
 9                 return mid
10             else:
11                 left = mid + 1
12         else:
13             right = mid - 1
14     return False
原文地址:https://www.cnblogs.com/kongzimengzixiaozhuzi/p/12957481.html