二分查找

来源:互联网 发布:java 线程之间通信 编辑:程序博客网 时间:2024/05/16 12:29

二分查找顾名思义,平分成两份查找(以网易云课堂 第六周作业为例,使用Python语言)

两点入门二分查找:

a. 猜测的值 = 中间值 =(low+high)/2 —— 二分的意义

b. 中间值<实际值,low = 中间值位置+1;中间值>实际值,high = 中间值-1

提供一个简易的代码模板(默认能够找到——如果不存在这个值也没必要查找了,提前使用in来判断是否存在):

def search(sequence, number, lower, upper):    if lower == upper:        assert number == sequence[upper] # 断言一定能找到,找不到则异常        return upper    else:        middle = (lower + upper)//2        if number > sequence[middle]:            return search(sequence, number, middle+1, upper)        else: # there has 2 situation--middle is not (middle-1)            return search(sequence,number,lower,middle)



一些实例:

1.定义一个 prime() 函数求整数 n 以内(不包括n)的所有素数(1不是素数),并返回一个按照升序排列的素数列表。使用递归来实现一个二分查找算法函数bi_search(),该函数实现检索任意一个整数在 prime() 函数生成的素数列表中位置(索引)的功能,并返回该位置的索引值,若该数不存在则返回 -1。

思考:

要查找位置并且返回索引值,一般解决方法很简单:使用循环判断 / 列表的index方法,但是要是列表很长东西很多,那么这样的从头开始循环的话则效率会很低,那么使用二分查找。

解:

说到递归函数,不得不再一次强调:一定要有终止条件返回;非终止条件的递归过程,调用自身前面一定要有return,否则返回的是None。

这道题中的终止条件便是:返回该位置的索引值,若该数不存在则返回 -1

def prime(n):    lst = []    for i in range(2, n):        for j in range(2, i):            if i % j == 0:                break        else:            lst.append(i)    return lstn = 10  # assume n = 10lst = prime(n)x = raw_input("Enter num: ")x = int(x) # raw_input() return a stringdef bi_search(x, low, high):    guess = (low + high) / 2    print lst[guess], x    if (x == lst[guess]):        return guess      elif low > high:        return -1    elif lst[guess] > x:        print 'lst[guess] > x'        return bi_search(x, low, guess -1) # !!! take care    elif lst[guess] < x:        return bi_search(x, guess + 1, high) # !!! take care

再次通过同学ZHT的启发,简化下程序:首先利用Python 的 “in” 运算符判断数字是否在列表内(先决条件),再进行查找。

既然循环的先决条件是有x 存在于列表当中,所以必然就是能够找到的 x 的位置的,故终止条件只有一个:x 的位置

def bi_serach(lst,n):    lenth = len(lst)    while n in lst:         if n == lst[lenth / 2]:            return lenth / 2        elif n < lst[lenth / 2]:            lst = lst[:lenth / 2]            return bi_serach(lst,n)        else:            lst = lst[lenth / 2 + 1:]            return bi_serach(lst,n) + lenth /2 + 1 # after slicing you must do    return -1 # same indent with "While"
上述程序有一个需要注意的地方:切片操作,往后切片之后一定要注意下标的变化要还原,之前提到过这样一个问题:“注意细节上的逻辑错误,在swap中,第二个参数不能够直接传mi,因为 mi 是在砍掉了 i 项之后的 nLst 中的位置 ≠ lst中的位置, 所以需要给mi 补上 i 才是 lst 中正确的位置。”

另外,使用循环实现二分查找:

同样需要找准终止条件,依然是:找到了 & 没找到的情况

逻辑是:没有找到就持续循环,找到了就return,故循环结束条件就是没有找到任何匹配position。

def bi_search(x, low, high):   while high >= low:       guess = (high + low) / 2       if x == lst[guess]:           return guess       elif lst[guess] > x:           high = guess - 1       else:           low = guess +1   return -1

当然,可以依照上述递归的方法也进行改装(循环的先决条件是,x 存在于列表当中),只需要将 while 条件(修改 while high >= low: )
while x in lst:
改变即可。


0 0
原创粉丝点击