• 查找算法:二分查找、插值查找、斐波那契查找


    二分查找

    查找的前提是数组有序

    思路分析

    代码实现(递归实现)

    1. # 二分查找(递归法实现)
    2. # 找到一个相等的值就返回该值的下标
    3. def binary_search(arr: list, find_val: int, left: int, right: int):
    4. mid = (left + right) // 2 # 寻找数组中间位置的下标
    5. if left > right: # 找不到元素,返回-1
    6. return -1
    7. if find_val == arr[mid]: # 找到了元素,返回元素在数组中的下标
    8. return mid
    9. elif find_val < arr[mid]: # 要找的元素比数组中间元素小,则继续在 mid 的左边寻找
    10. return binary_search(arr, find_val, left, mid - 1)
    11. else: # 要找的元素比数组中间元素大,则继续在 mid 的右边寻找
    12. return binary_search(arr, find_val, mid + 1, right)
    13. arr = [4, 8, 9, 10, 12, 14, 15]
    14. res = binary_search(arr, 0, 0, len(arr) - 1)
    15. print(res)
    16. # 二分查找(递归法实现)
    17. # 如果数组中有多个值和要查找的值相等,则把它们的下标都返回
    18. def binary_search2(arr: list, find_val: int, left: int, right: int):
    19. mid = (left + right) // 2 # 寻找数组中间位置的下标
    20. if left > right: # 找不到元素,返回-1
    21. return []
    22. if find_val == arr[mid]: # 找到了元素,返回元素在数组中的下标
    23. # 找到了元素,先把当前的下标放入到一个列表中
    24. # 再依次从该位置开始向左和向右查找,还有没有其他相等的值
    25. index_pos = []
    26. index_pos.append(mid)
    27. temp = mid - 1
    28. while True: # 向左查找
    29. if temp < left or arr[temp] != find_val:
    30. break
    31. index_pos.append(temp)
    32. temp -= 1 # temp 左移
    33. temp = mid + 1
    34. while True: # 向右查找
    35. if temp > right or arr[temp] != find_val:
    36. break
    37. index_pos.append(temp)
    38. temp += 1 # temp 右移
    39. return index_pos
    40. elif find_val < arr[mid]: # 要找的元素比数组中间元素小,则继续在 mid 的左边寻找
    41. return binary_search2(arr, find_val, left, mid - 1)
    42. else: # 要找的元素比数组中间元素大,则继续在 mid 的右边寻找
    43. return binary_search2(arr, find_val, mid + 1, right)
    44. arr = [4, 8, 9, 10,10, 12, 14, 15]
    45. res = binary_search2(arr, 0, 0, len(arr) - 1)
    46. print(res)

    代码实现(非递归实现)

    1. # 二分查找的非递归实现
    2. def binary_search(arr: list, target: int):
    3. """
    4. 二分查找的非递归实现
    5. :param arr: 要查找的有序数组
    6. :param target: 要查找的值
    7. :return: 要查找值的下标,找不到返回-1
    8. """
    9. left = 0
    10. right = len(arr) - 1
    11. while left <= right:
    12. mid = (left + right) // 2
    13. if target == arr[mid]:
    14. return mid
    15. elif target < arr[mid]:
    16. right = mid - 1
    17. else:
    18. left = mid + 1
    19. return -1
    20. res = binary_search([1, 2, 5, 7, 9, 10, 12], 12)
    21. print(res)

    插值查找

    查找的前提是数组有序

    思路分析

    当数组为[1, 2, 3, 4, 5, ..., 100] 时,加入此时要查找1,那么二分查找的方法会进行多次递归才能找到,效率较低,所以有了插值查找方法。插值查找适用于数据比较连续的情况下。

    代码实现

    1. # 插值查找
    2. def insert_value_search(arr: list, find_val: int, left: int, right: int):
    3. # 找不到元素,返回-1
    4. # 条件 find_val < arr[left] or find_val > arr[right] 要有,否则mid可能会越界
    5. if left > right or find_val < arr[left] or find_val > arr[right]:
    6. return -1
    7. # 寻找数组中间位置的下标
    8. mid = left + (right - left) * (find_val - arr[left]) // (arr[right] - arr[left])
    9. mid_val = arr[mid]
    10. if find_val == mid_val: # 找到了元素,返回元素在数组中的下标
    11. return mid
    12. elif find_val < mid_val: # 要找的元素比数组中间元素小,则继续在 mid 的左边寻找
    13. return binary_search(arr, find_val, left, mid - 1)
    14. else: # 要找的元素比数组中间元素大,则继续在 mid 的右边寻找
    15. return binary_search(arr, find_val, mid + 1, right)
    16. arr = []
    17. for i in range(100):
    18. arr.append(i + 1)
    19. res = insert_value_search(arr, 3, 0, len(arr) - 1)
    20. print(res)

    斐波那契查找

    查找的前提是数组有序

    思路分析

    代码实现

    1. import copy
    2. # 斐波那契查找
    3. # 因为算法中需要用到斐波那契数列,所以此处用非递归的方法构造一个斐波那契数列
    4. def fib(size: int) -> list:
    5. f = []
    6. f.append(1)
    7. f.append(2)
    8. i = 2
    9. while i < size:
    10. f.insert(i, f[i - 1] + f[i - 2])
    11. i += 1
    12. return f
    13. # 非递归方式实现斐波那契查找算法
    14. def fibonacci_search(arr, key):
    15. low = 0
    16. high = len(arr) - 1
    17. k = 0 # 表示斐波那契分割数值的下标
    18. mid = 0 # 存放 mid 值
    19. f = fib(20) # 获取斐波那契数列
    20. # 获取斐波那契分割数值的下标
    21. while high > f[k] - 1:
    22. k += 1
    23. # 因为f[k]的值可能大于arr的长度,因此需要对数组进行扩容(新构造一个数组)
    24. # 让数组的长度等于f[k],新增加的长度的下标用arr数组最后的数填充
    25. # 如:arr=[1,8,10,89,1000,1234] f[k] = 8
    26. # 扩容后:temp=[1,8,10,89,1000,1234,1234,1234]
    27. temp = copy.deepcopy(arr)
    28. i = high + 1
    29. while i < f[k]:
    30. temp.append(arr[high])
    31. i += 1
    32. # 使用 while 来循环处理,找到要查找的key
    33. while low <= high: # 只要条件满足就可以继续查找
    34. mid = low + f[k - 1] - 1
    35. if key < temp[mid]: # 应该继续向数组的前面查找(左边)
    36. high = mid - 1
    37. """
    38. k -= 1 说明:
    39. 数组全部元素 = 前面(左边)的元素 + 后面(右边)的元素
    40. 斐波那契数列:f[k] = f[k - 1] + f[k - 2]
    41. 因为前面有f[k - 1]个元素,所以可以继续拆分:f[k - 1] = f[k - 2] + f[k - 3]
    42. 即在f[k - 1] 的前面继续查找,即下次循环 mid = f[k - 1 - 1] - 1
    43. """
    44. k -= 1
    45. elif key > temp[mid]: # 应该继续向数组的后面查找(右边)
    46. low = mid + 1
    47. """
    48. k -= 2 说明:
    49. 数组全部元素 = 前面(左边)的元素 + 后面(右边)的元素
    50. 斐波那契数列:f[k] = f[k - 1] + f[k - 2]
    51. 因为后面有f[k - 2]个元素,所以可以继续拆分:f[k - 2] = f[k - 3] + f[k - 4]
    52. 即在f[k - 2] 的前面继续查找 k-=2,即下次循环 mid = f[k - 1 - 2] - 1
    53. """
    54. k -= 2
    55. else: # 找到
    56. # 确定返回的是哪个下标
    57. if mid <= high:
    58. return mid
    59. return high
    60. # 找不到,返回-1
    61. return -1
    62. arr=[1,8,10,89,1000,1234]
    63. res = fibonacci_search(arr, 8)
    64. print(res)

  • 相关阅读:
    深入理解java虚拟机:虚拟机字节码执行引擎(3)
    2021年北京高校数学建模校际联赛题目出版社图书印制策略解题论文及程序
    《操作系统真象还原》第一章 部署工作环境
    STM32F1网络编程-TCP服务器(基于W5500网卡)
    USB4之ASM2464PD与ASM2464PDX兼容与运用
    高频更新使用sse好还是WebSocket
    QT最小化到托盘显示
    亚马逊鲲鹏系统全自动化功能有哪些
    三层内网 外网打点到内网域 sec123 复现
    关于极客时间 | MySQL实战45讲的部分总结
  • 原文地址:https://blog.csdn.net/2301_77659011/article/details/133845039