分治算法(一)二分搜索技术

分治算法的本质就是将一个大规模的问题分解为若干个小规模的相同子问题,分而治之。
1.分治算法简述
1.1分治算法也有它的适用条件,满足以下3个条件,才能使用分治法来解决:

(1)原问题可分解为若干个规模较小的相同子问题
(2)子问题相互独立
(3)子问题的解可以合并为原问题的解

1.2使用分治法解题的步骤:

(1)分解:将要解决的问题分解为若干个规模较小、相互独立、与原问题形式相同的子问题。
(2)治理:对子问题进行求解。
(3)合并:按原问题的要求,将子问题的解逐层合并构成原问题的解。

2.用二分搜索技术玩猜数字游戏
2.1问题描述
假如你女朋友想跟你玩一个游戏,说:“亲爱的,猜一下我心里想的是哪个数字?这个数字在1~10范围内。”你可能会猜1,女朋友说:“小了。”接着你猜2,女朋友说:“小了。”接着你又猜3,女朋友还是说:“小了。”这时候女朋友会很无奈地说:“天呐,你怎么可以这么笨!”这样每次加1的方法来猜,如果给定的数字是1,那么很幸运,一次就能猜中;但是如果给定的是10,用这种方法就需要猜10次。
推广开来,如果是n个数,使用这种方法最坏的情况要猜n次才能成功。如何能够用最少次数猜中给定的数字?我们的二分查找(也叫折半查找)可以很好地解决这个问题。就拿上面问题为例,因为这些数字(1到10)是有序(升序)的,使用二分查找每次和中间元素比较,如果提示说猜的数字比给定的数字小了,即给定数字比中间元素大,则在后半部分查找;如果提示说猜的数字比给定的数字大了,即给定数字比中间元素小,则在前半部分查找。这样每次查找,问题都会缩小为上次问题规模的一半,所以也被称为折半查找。
2.2算法设计
用列表num[]存储该有序序列(假定为升序),设变量low表示查找范围的下界,high表示查找范围的上界,middle表示查找范围的中间位置,x为特定的查找元素。
(1)初始化。令low=0,即指向有序列表num[]的第一个元素(列表元素下标从0开始);high=n-1,即指向有序列表num[]的最后一个元素,n表示列表长度,也就是列表元素的个数。
(2)middle=(low+high)/ 2,即指向查找范围的中间元素。(low+high)为奇数的话,除以2并不能得到整数,但是列表中元素的下标都是整数,这里实际上是向下取整,比如:3.5向下取整为3。
(3)判定 low<=high 是否成立,如果成立,转第4步,否则,说明该列表中没有指定元素,算法结束。
(4)判断 x 与 num[middle] 的关系。如果 x=num[middle],搜索成功,算法结束;如果 x>num[middle],令 low=middle+1;如果 x<num[middle],令 high=middle-1,转为第2步。

2.3算法实现
(1)非递归实现

numList = []
#定义一个计数变量,统计查找次数
count = 1 

def BinarySearch(numList,x):
    low = 0
    high = len(numList) - 1
    global count
    while(low <= high):
        #地板除向下取整
        middle = (low + high) // 2
        if x == numList[middle]:
            #指定元素等于中间元素,查找成功,返回元素下标
            return middle
        elif x < numList[middle]:
            #指定元素小于中间元素,到前半部分查找
            high = middle - 1
            count = count + 1
        else:
            #指定元素大于中间元素,到后半部分查找
            low = middle + 1
            count = count + 1
    return None


n = int(input('请输入数列中的元素个数n为:'))
for i in range(n):
    number = int(input('请依次输入数列中的元素:'))
    numList.append(number)

# 列表的sort函数,默认为升序
numList.sort()
print('升序排序后的列表为:',numList)
x = int(input('请输入要查找的元素:'))
index = BinarySearch(numList,x)
print('共查找了',count,'次!')
if index == None:
    print('该列表中没有要查找的元素!')
else:
    print('要查找的元素:',x,',在列表中的位置为:',index+1)

测试:

请输入数列中的元素个数n为:7
请依次输入数列中的元素:16
请依次输入数列中的元素:30
请依次输入数列中的元素:22
请依次输入数列中的元素:31
请依次输入数列中的元素:63
请依次输入数列中的元素:12
请依次输入数列中的元素:56
升序排序后的列表为: [12, 16, 22, 30, 31, 56, 63]
请输入要查找的元素:16
共查找了 2 次!
要查找的元素: 16 ,在列表中的位置为: 2

(2)递归实现

def recusionBS(numList,x,low,high):
    if low > high:
        return None
    middle = (low + high) // 2
    if x == numList[middle]:
        return middle
    elif x < numList[middle]:
        return recusionBS(numList,x,low,middle-1)
    else:
        return recusionBS(numList,x,middle+1,high)

index = recusionBS([1,2,3,4,5],2,0,4)
print('要查找的元素下标是:',index)

测试:

要查找的元素下标是: 1
  • 7
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值