Leader笑着对我说:孩子10分钟搞懂二分查找,不然世界这么大你就得去看看了

深夜来临我还不想入睡,无聊的我想起已经好几天没有更新文章,不知道写点什么,我突然想到我对于算法这方面的知识还是太浅
所以我决定在开一个专栏,就叫做 数据结构和算法的混合双打

二分查找

二分法是一个查找算法,就是在一堆数据集里面找到你想要的那个数据

条件:

        数据必须是有序序列
        例如: [12,15,86,95,105,334,911,1000] 可以不是连续的,但是必须要是从小到大排列的,不能违背这个原则,这同样也是它的一个小小小小小 缺点

核心思想:

        掐头结尾取中间

优点:

        我称它为查找界的鼻祖,查找速度快,效率极高

好的概念就说这么多,接下来代码 showtime!!

一、最最最low 的写法
# 我们先来搞一个数组吧
list01 = [20, 45, 56, 79, 90, 110, 221, 285, 356, 618, 985, 1004]

# 接收要查找的数字
num = int(input("请输入你要查找的数字:"))

## 假如我们不用算法的情况下,是不是就像下面这样写

for item in list01:
	if num == item:
	print("啊我找到了")
	break

这样就是我把列表的每一项拿出来,一个一个对比,如果相等就找到了,没找到就一直找,什么时候找到算什么时候

这种查找为什么low呢,因为,你数据量少的时候,你可以这样写,那假如要是从几亿几十亿数据里面找,那么你这样就要找几亿几十亿次,就显得效率特别低

二、高级的算法:二分法查找
# 二分法查找核心思想:掐头结尾取中间 

# 位置	   left                mid    						 right
# 索引       0	1	2	3	4	5	 6	  7	   8	9	 10	  11	     
# list01 = [20, 45, 56, 79, 90, 110, 221, 285, 356, 618, 985, 1004]

# 找到 头 和 尾
left = 0   # 取得列表的头部,这个最开始是 20 ,那么它的索引就是 0 
right = len(list01) -1   # 尾部是1004, 那么索引就是 11 

# 取中间
mid = (left + right) // 2  # 左边加右边等于索引0+11,然后整除于2 

注意: 必须整除,因为你要是 / 2 的话,就容易出现小数点 .5 这样的,在我们 索引中是没有点几 这个概念的

接下来我们为了演示输入一个存在的数字90,然后和中间的mid这个数做比较,那么我们在现在中间的是110
90比110小,且列表是从小到大排列的,所以这个数字绝对不可能出现在列表的右边

一定会出现在列表的左边,那么我们就应该去移动右边界到mid的前一位
也就是:

# 位置	   left           right mid    						 
# 索引       0	1	2	3	4	5	 6	  7	   8	9	 10	  11	     
# list01 = [20, 45, 56, 79, 90, 110, 221, 285, 356, 618, 985, 1004]

那么反之就是比中间数字大,就是right不变,left向右移动呗

根据上面的分析所以接下来我们就写算法过程了:

if num > list01[mid]:
    left = mid + 1
elif num < list01[mid]:
    right = mid - 1
else:
    print("我找到啦,这个数字在%s位置" % mid)

这样我们的大致的算法主体逻辑就写完了,但是这样写只是写了一步,我只是计算了第一次
也就是第一次移动,我们不能保证它移动一次就找到了

所以接下来我们应该是类似于这样写,加一个循环,然后让它一直找,找到直接break

while 1:
	# 要一直定义中间值
    mid = (left + right) // 2
    if num > list01[mid]:
        left = mid + 1
    elif num < list01[mid]:
        right = mid - 1
    else:
        print("我找到啦,这个数字在%s位置" % mid)
        break

那么我们千算万算还是欠点考虑,就是那你输入的这个数字不存在怎么办,我输入了一个60
它就会一直找找找,不断循环,因为left是要一直加1,而right是要一直减1
总有一次 left会到right左边,right会到left右边,这样就代表左右都找过了,我们在找下去就没有意义了

# 位置	         right left    			  		 
# 索引       0	1	2	3	4	5	 6	  7	   8	9	 10	  11	     
# list01 = [20, 45, 56, 79, 90, 110, 221, 285, 356, 618, 985, 1004]

所以我们代码最终应该是这样的:

list01 = [20, 45, 56, 79, 90, 110, 221, 285, 356, 618, 985, 1004]

num = int(input("请输入你要查找的数字:"))
left = 0
right = len(list01) - 1

while left <= right:  # 当左边比右边小的时候才有意义,反之不存在
	# 要一直定义中间值
    mid = (left + right) // 2
    if num > list01[mid]:
        left = mid + 1
    elif num < list01[mid]:
        right = mid - 1
    else:
        print("我找到啦,这个数字在%s位置" % mid)
        break
else:
    print("抱歉,你找数字不存在")

我上面说它的效率是非常高的,我们举个例子:

# 一亿数据,用二分查找
1100000000   
250000000
325000000
4.....

最终我们可以计算出查找一亿数据最多只要二分查找27次,就可以全部找一遍
也就是2的几次方,我们去转换成log以2为底的对数进行计算
https://blog.csdn.net/Yxh666

  • 37
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 94
    评论
评论 94
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨旭华 

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值