二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构

代码实现

  1. def binary_search(arr: list, target: int) -> int:
  2. """
  3. 非递归版本
  4. """
  5. # 数据的范围
  6. l, r = 0, len(arr) - 1
  7. while l <= r:
  8. # mid = (l+r) // 2 会存在越界
  9. mid = l + (r - l) // 2
  10. if arr[mid] == target:
  11. return mid
  12. if target > arr[mid]:
  13. # 需要查找的数据在右边数组中
  14. l = mid + 1
  15. else:
  16. # 需要查找的数据在左边的数组中
  17. r = mid - 1
  18. return -1
  19. def binary_search(arr: list, target: int, l: int, r: int) -> int:
  20. """
  21. 递归版本
  22. """
  23. # 数据的范围
  24. if l > r:
  25. return -1
  26. mid = l + (r - l) // 2
  27. if arr[mid] == target:
  28. return mid
  29. if target > arr[mid]:
  30. # 需要查找的数据在右边数组中
  31. l = mid + 1
  32. else:
  33. # 需要查找的数据在左边的数组中
  34. r = mid - 1
  35. return binary_search(arr=arr, target=target, l=l, r=r)

二分查找变种

  1. class BinarySearch:
  2. @staticmethod
  3. def binary_search(arr: list, target: int) -> int:
  4. """
  5. 二分查找非递归版本
  6. """
  7. # 数据的范围
  8. l, r = 0, len(arr) - 1
  9. while l <= r:
  10. # mid = (l+r) // 2 会存在越界
  11. mid = l + (r - l) // 2
  12. if arr[mid] == target:
  13. return mid
  14. if target > arr[mid]:
  15. # 需要查找的数据在右边数组中
  16. l = mid + 1
  17. else:
  18. # 需要查找的数据在左边的数组中
  19. r = mid - 1
  20. return -1
  21. def binary_search_r(self, arr: list, target: int, l: int, r: int) -> int:
  22. """
  23. 二分查找递归版本
  24. """
  25. # 数据的范围
  26. if l > r:
  27. return -1
  28. mid = l + (r - l) // 2
  29. if arr[mid] == target:
  30. return mid
  31. if target > arr[mid]:
  32. # 需要查找的数据在右边数组中
  33. l = mid + 1
  34. else:
  35. # 需要查找的数据在左边的数组中
  36. r = mid - 1
  37. return self.binary_search_r(arr=arr, target=target, l=l, r=r)
  38. @staticmethod
  39. def binary_upper(data: list, target: int) -> int:
  40. # 寻找大于 target的最小值的下标
  41. l, r = 0, len(data)
  42. while l < r:
  43. mid = l + (r - l) // 2
  44. if data[mid] <= target:
  45. l = mid + 1
  46. else:
  47. # 可能当前mid表示的值就是大于target 且是最小值
  48. r = mid
  49. return l
  50. @staticmethod
  51. def binary_lower(data: list, target: int) -> int:
  52. """ 寻找小于 target值的最大值下标 """
  53. # 在 [l,r] 中找解
  54. l, r = -1, len(data) -1
  55. while l < r:
  56. mid = l + (r - l +1) // 2
  57. if data[mid] < target:
  58. l = mid
  59. else:
  60. r = mid -1
  61. return l
  62. def binary_ceil(self, data: list, target: int) -> int:
  63. """
  64. 天花板
  65. 找到原始数据中值为target的最大索引
  66. 如果没有返回>target的最小值索引
  67. """
  68. u = self.binary_upper(data, target)
  69. if data[u - 1] == target and u - 1 >= 0:
  70. return u - 1
  71. return u

时间复杂度

O(logn)