zoukankan      html  css  js  c++  java
  • 二分查找算法

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

    先来看版本一:

     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次,是相当快的

  • 相关阅读:
    Calling a parent window function from an iframe
    JSON with Java
    Posting array of JSON objects to MVC3 action method via jQuery ajax
    What's the difference between jquery.js and jquery.min.js?
    jquery loop on Json data using $.each
    jquery ui tabs详解(中文)
    DataTables warning requested unknown parameter
    Datatables 1.10.x在命名上与1.9.x
    jQuery 1.x and 2.x , which is better?
    DataTabless Add rows
  • 原文地址:https://www.cnblogs.com/zzliu/p/10409138.html
Copyright © 2011-2022 走看看