python有序查找算法:二分法

常见的搜索方法:顺序查找、二分法查找、二叉树查找、哈希查找。

二分查找针对有序的一组数列

 

二分查找:
我们手里有一个长度为n的正序数列,当我们想查找一个数 x是否在这个数列当中的时候
1 取数列正中间的数mid,
如果mid和x相等,则找到结果,查找成功 返回True
如果mid比x大,则x应该在mid的左侧,我们把mid左侧当作一个新的数列li
如果mid比x小,则x应该在mid的右侧,我们把mid右侧当作一个新的数列li
2 对于新的数列li 进行1的查找工作

3 一直重复上面查找,生成新的数列li为空的时候则 数列当中没有数x 返回False

时间复杂度:最优O(1) 我们取第一次中间数mid 找到了 这种概率很低
最坏O(log n) 假设n个数的数列,每次把数列分成两半,n除以多少次2 等于1 呢? log n次

二分法查找

二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。


 python有序查找算法:二分法_第1张图片

二分法查找算法有递归和非递归两种方法。

  1. import sys  
  2.   
  3. def search2(a,m):  
  4.     low = 0  
  5.     high = len(a) - 1  
  6.     while low<=high:  
  7.         mid = (low + high)/2  
  8.         midval = a[mid]  
  9.   
  10.         if midval
  11.             low = mid + 1  
  12.         elif midval>m:  
  13.             high = mid-1  
  14.         else:  
  15.             print mid  
  16.             return mid  
  17.     print -1  
  18.     return -1  
  19.   
  20. if __name__ == "__main__":  
  21.   
  22.     a = [int(i) for i in list(sys.argv[1])]  
  23.     m = int(sys.argv[2])  
  24.     search2(a,m)  

 

 

 '''
二分法查找
sequence 查找的序列,范围
number   查找目标
lower    下限
upper    上限    
'''
def search(sequence, number, lower, upper):
    if lower == upper:
        assert number == sequence[upper]
        return upper
    else:
        middle = (lower + upper) // 2 #找到两者的中间点
        if number > sequence[middle]: 
            #如果在中间点的右侧,就在middle+1 ~ upper的范围内继续找
            return search(sequence, number, middle+1, upper)
        else:
            #如果在中间点的左侧,就在lower~middle的范围继续找
            return search(sequence, number, lower, middle)          
#初始化一个1~100的列表
seq = []
for x in xrange(1,101):
    seq.append(x)
print search(seq, 86, 0, 100)

 

 

二分法是一种快速查找的方法,时间复杂度低,逻辑简单易懂,总的来说就是不断的除以2除以2...

但是需要注意:

待查找的序列区间单调有序

 

例如需要查找有序数组arr里面的某个关键字key的位置,那么首先确认arr的中位数或者中点center,下面分为三种情况:

1

2

3

假如arr[center]>key,说明key在arr中心左边范围;

假如arr[center]

假如arr[center]=key,说明key在arr中心。

范围每次缩小一半,写个while的死循环知道找到为止。

二分法查找非常快且非常常用,但是唯一要求是要求数组是有序的

我的另一篇博客刚好介绍了冒泡排序可以去看看:

1

http://www.cnblogs.com/TTyb/p/5726151.html

首先我们用递归的方式实现二分查找算法:

#递归实现二分查找 li是列表   item是要查找的元素
def merge_search( li ,item ):
    #传来的列表每次都是新生成的,如果发现里面没有元素,则是查找到尽头都没找到
    if not li :
        return False

    mid = len(li)//2   #mid记录li的中间位置
    #检查一下 如果中间这个数就是要找的元素 返回真
    if li[mid] == item :
        return True
    # 如果mid比item大,说明item可能会出现在mid左边,对左边再查找
    elif li[mid]> item :
        return merge_search( li[:mid] ,item )
    # mid 比item小,说明item有可能在mid右边,对右边再查找
    else :
        return merge_search( li[mid+1:] , item )

if __name__ == '__main__':
    li = [1,2,3,4,5,6,7]
    print( merge_search(li , 0) )   #False
    print( merge_search(li , 1) )   #True

下面我们尝试用while循环去实现二分查找:

def merge_search( li , item ):
    #获取li的开始 结束
    start = 0
    end = len(li)-1

    #只要start和end 还没错开 就一直找
    while start <= end :
        #通过计算获取当前查找范围的中间位置
        mid = (start + end)//2
        #如果中间数就是item则返回True
        if li[mid] == item :
            return True
        #如果mid比item大,说明item可能会出现在mid左边,对左边再查找
        elif li[mid]> item :
            end = mid - 1
        # mid 比item小,说明item有可能在mid右边,对右边再查找
        else :
            start = mid + 1
    #跳出循环说明没找到 返回错误
    return False

if __name__ == '__main__':
    li = [1,2,3,4,5,6,7,8]
    print( merge_search(li , 8) ) #True
    print( merge_search(li , 0) ) #False

以上就是两种实现二分查找的方法。

因为思想相同,他们的时间复杂度是一样的。

但是递归的方式,每次都要开新的列表,实际上空间复杂度会更大一些。

 

二分法的代码如下:

 

#!/usr/bin/python3.4
# -*- coding: utf-8 -*-

def BinarySearch(arr, key):
    # 记录数组的最高位和最低位
    min = 0
    max = len(arr) - 1

    if key in arr:
        # 建立一个死循环,直到找到key
        while True:
            # 得到中位数
            # 这里一定要加int,防止列表是偶数的时候出现浮点数据
            center = int((min + max) / 2)
            # key在数组左边
            if arr[center] > key:
                max = center - 1
            # key在数组右边
            elif arr[center] < key:
                min = center + 1
            # key在数组中间
            elif arr[center] == key:
                print(str(key) + "在数组里面的第" + str(center) + "个位置")
                return arr[center]
    else:
        print("没有该数字!")


if __name__ == "__main__":
    arr = [1, 6, 9, 15, 26, 38, 49, 57, 63, 77, 81, 93]
    while True:
        key = input("请输入你要查找的数字:")
        if key == " ":
            print("谢谢使用!")
            break
        else:
            BinarySearch(arr, int(key))

python有序查找算法:二分法_第2张图片

 

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

# -*- coding: utf-8 -*-

def BinarySearch(arr, key):

 # 记录数组的最高位和最低位

 min = 0

 max = len(arr) - 1

 if key in arr:

  # 建立一个死循环,直到找到key

  while True:

   # 得到中位数

   # 这里一定要加int,防止列表是偶数的时候出现浮点数据

   center = int((min + max) / 2)

   # key在数组左边

   if arr[center] > key:

    max = center - 1

   # key在数组右边

   elif arr[center] < key:

    min = center + 1

   # key在数组中间

   elif arr[center] == key:

    print(str(key) + "在数组里面的第" + str(center) + "个位置")

    return arr[center]

 else:

  print("没有该数字!")

if __name__ == "__main__":

 print("脚本之家测试结果:")

 arr = [1, 6, 9, 15, 26, 38, 49, 57, 63, 77, 81, 93]

 while True:

  key = raw_input("请输入你要查找的数字:")

  if key == " ":

   print("谢谢使用!")

   break

  else:

   BinarySearch(arr, int(key))

 

 

你可能感兴趣的:(python有序查找算法:二分法)