二分查找及简单应用

二分查找

  • 又称折半查找。
  • 优点:是比较次数少,查找速度快,平均性能好。
  • 缺点:是要求待查表为有序表,且插入删除困难。
  • 适用于不经常变动而查找频繁的有序列表。
  • 过程:首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
def BinarySearch(key, lst):
    lo = 0
    hi = len(lst) - 1
    while lo <= hi:
        mid = lo + (hi - lo)/2
        if lst[mid] > key:
            hi = mid - 1
        elif lst[mid] < key:
            lo = mid + 1
        else:
            return mid
    return -1

简单应用

题目:找出一个序列(N个数)中三个相加和等于0的数,并打印。

  • 方法一:三层for循环——运行时间的增长数量级为立方级别: N3
def ThreeSum(l):
    N = len(l)
    results = []
    for i in xrange(N):
        for j in xrange(i+1, N):
            for k in xrange(j+1, N):
                if l[i] + l[j] + l[k] == 0:
                    results.append((l[i], l[j], l[k]))
    return results

if __name__ == '__main__':
    print ThreeSum([1,2,3,4,5,6,-3,-7,-11])

----------
输出:
[(-11, 5, 6), (-7, 1, 6), (-7, 2, 5), (-7, 3, 4), (-3, 1, 2)]
  • 方法二:借助二分查找——运行时间的增长数量级为对数级别: N2logN
    • 改进后的算法思想:当且仅当-(a[i]-a[j])在数组中时,才满足条件。
    • 下面的代码会将数组排序并进行N(N-1)/2次二分查找,每次查找所需要的时间都和logN成正比。因此,总的运行时间和 N2logN 成正比。这个解法也使我们能够解决更大规模的问题。
def BinarySearch(key, lst):
    lo = 0
    hi = len(lst) - 1
    while lo <= hi:
        mid = lo + (hi - lo)/2
        if lst[mid] > key:
            hi = mid - 1
        elif lst[mid] < key:
            lo = mid + 1
        else:
            return mid
    return 

def sum_3(l, BinarySearch):
    l = sorted(l)#先排序
    N = len(l)
    results = []
    for i in xrange(N):
        for j in xrange(i+1, N):
            if BinarySearch(-l[i]-l[j], l) > j:
                results.append((l[i], l[j], -l[i]-l[j]))
    return results

if __name__ == '__main__':
    print sum_3([1,2,3,4,5,6,-3,-7,-11], BinarySearch)

----------
输出:
[(-11, 5, 6), (-7, 1, 6), (-7, 2, 5), (-7, 3, 4), (-3, 1, 2)]

目前数据规模较小,体现不出方法二的时间优势。接下来,我们再做一个测试,观察效果:

import time

def ThreeSum(l):
    N = len(l)
    results = []
    for i in xrange(N):
        for j in xrange(i+1, N):
            for k in xrange(j+1, N):
                if l[i] + l[j] + l[k] == 0:
                    results.append((l[i], l[j], l[k]))
    return results

def BinarySearch(key, lst):
    lo = 0
    hi = len(lst) - 1
    while lo <= hi:
        mid = lo + (hi - lo)/2
        if lst[mid] > key:
            hi = mid - 1
        elif lst[mid] < key:
            lo = mid + 1
        else:
            return mid
    return 

def sum_3(l, BinarySearch):
    l = sorted(l)#先排序
    N = len(l)
    results = []
    for i in xrange(N):
        for j in xrange(i+1, N):
            if BinarySearch(-l[i]-l[j], l) > j:
                results.append((l[i], l[j], -l[i]-l[j]))
    return results    

if __name__ == '__main__':
    time_start = time.time()
    sum_3([i for i in xrange(-500, 500)], BinarySearch)
    time_end = time.time()
    print '方法一运行时间:'+str(time_end - time_start)

    time_start = time.time()
    ThreeSum([i for i in xrange(-500, 500)])
    time_end = time.time()
    print '方法二运行时间:'+str(time_end - time_start)

输出:

方法一运行时间:0.558466911316
方法二运行时间:9.34502387047
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值