• 二分查找算法


    二分查找是一个很常用的算法,用于在有序数组中查找指定元素的索引

    先来看版本一:

     1 def bin_search(lst, a):
     2     """
     3     二分查找函数
     4     lst: 序列,默认升序
     5     a: 要查找的值
     6     返回值: a的索引,找不到返回None
     7     """
     8     if a == lst[len(lst) // 2]:
     9         return len(lst) // 2
    10     elif a < lst[len(lst) // 2]:
    11         bin_search(lst[:len(lst) // 2], a)
    12     else:
    13         bin_search(lst[(len(lst)+1) // 2:], a)

    这种方法存在以下几点错误:

    (1)第11、13行递归时没有返回值,这是一个很低级的错误!

    (2)此算法中对列表进行了切片,切片之后索引就变了,返回的索引就不是原列表的索引

    版本二:

     1 def bin_search(lst, num, start=None, end=None):
     2     """
     3     二分查找
     4     :param lst: 列表
     5     :param num: 目标元素
     6     :param start: 查找的起始位置
     7     :param end: 查找的终止位置
     8     :return: 返回索引,找不到返回None
     9     """
    10     start = start if start else 0
    11     end = end if end else len(lst)-1
    12     mid = (end - start)//2 + start
    13     if start > end:
    14         return None
    15     elif num == lst[mid]:
    16         return mid
    17     elif num < lst[mid]:
    18         bin_search(lst, num, start, mid-1)
    19     else:
    20         bin_search(lst, num, mid+1, end)

    二分查找的效率是很高的,因为每调用一次查找范围就减半,因此只需要很少的次数就可以找到目标元素。

    为了查看函数调用的次数,我写了一个简单的装饰器来输出函数递归调用的次数,完整代码如下:

     1 import time
     2 
     3 def call_num(func):
     4     """
     5     此装饰器函数用于计算函数调用次数
     6     :param func:
     7     :return:
     8     """
     9     num = 0
    10 
    11     def inner(*args, **kwargs):
    12         nonlocal num
    13         ret = func(*args, **kwargs)
    14         num += 1
    15         print("function called number:", num)
    16         return ret
    17     return inner
    18 
    19 
    20 @call_num
    21 def bin_search(lst, num, start=None, end=None):
    22     """
    23     二分查找
    24     :param lst: 列表
    25     :param num: 目标元素
    26     :param start: 查找的起始位置
    27     :param end: 查找的终止位置
    28     :return: 返回索引,找不到返回None
    29     """
    30     start = start if start else 0
    31     end = end if end else len(lst)-1
    32     mid = (end - start)//2 + start
    33     if start > end:
    34         return None
    35     elif num == lst[mid]:
    36         return mid
    37     elif num < lst[mid]:
    38         bin_search(lst, num, start, mid-1)
    39     else:
    40         bin_search(lst, num, mid+1, end)
    41 
    42 l1 = []
    43 
    44 for i in range(100000000):
    45     l1.append(i)
    46 start_time = time.time()
    47 print(bin_search(l1, 83374292))
    48 end_time = time.time()
    49 print(end_time-start_time)

    执行结果

    function called number: 1
    function called number: 2
    function called number: 3
    function called number: 4
    function called number: 5
    function called number: 6
    function called number: 7
    function called number: 8
    function called number: 9
    function called number: 10
    function called number: 11
    function called number: 12
    function called number: 13
    function called number: 14
    function called number: 15
    function called number: 16
    function called number: 17
    function called number: 18
    function called number: 19
    function called number: 20
    function called number: 21
    function called number: 22
    function called number: 23
    function called number: 24
    function called number: 25
    83374292
    0.008976936340332031

    可见查找1亿条数据只需要0.009秒,函数调用了25次,是相当快的

  • 相关阅读:
    UBI FAQ and HOWTO
    Is an MTD device a block device or a char device?
    使用apt-mirror建立本地debian仓库源
    在SpringMVC中获取request对象的几种方式
    spring mvc提交日期类型参数
    Java 获取指定日期的方法汇总
    CentOS 7 安装tomcat
    CentOS 7 安装和配置JDK
    CentOS7 yum 安装git
    Java List合并去重
  • 原文地址:https://www.cnblogs.com/zzliu/p/10409138.html
Copyright © 2020-2023  润新知