回复
数据结构与算法第四天 原创
Piwriw.
发布于 2022-1-21 15:28
浏览
0收藏
前言
- 这是我在51CTO春节不停更,此文正在参加「星光计划-春节更帖活动」第五天的第五篇文章了,昨天我跟大家分享了一下数据结构之栈Stack和队列Queue,今天我想跟大家分享一个新的查找算法—:star2:二分查找:star2:,二分查找其实是经常会遇上的一种不太复杂的优化查找算法,其本身存在有着很大的意义,今天在二分查找中,我们还会学习到一个非常有意思的“新事物”—递归,废话不多说,Let is get it!
- 由于我本身能力限制,我分享的内容更偏向于新手向,但是我希望大家有耐心看完的话,一定会有自己的感悟
- 由于本人能力有限,在过程中难免会出现错误,以及可能也有存在更好的代码,希望大家在评论区发现错误也能留言,大家一起来讨论这个问题:two_hearts:
什么是二分查找
二分查找在百度百科的定义:
- 二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列
二分查找正如它的名字,我们也叫做折半查找,每次查找都能锁定排除了一半的空间,所以我们二分查找的每次时间就是n,n/2,n/4…,所以二分查找的时间复杂度为O(logn),又因为二分查找不是一种不稳定的查找,最坏情况下它的时间复杂度为O(n)
- $\color{ff0000}{特别提醒,二分查找本身只能使用在有序的情况下,所以我们这里没有添加上我们排序的时间}$
为什么要学习二分查找
-
- 二分查找本身,首先运行效率达到了比较高的O(logn),这个级别运算效率足够快
-
- 二分查找本身我个人认为是理解之后的树的重要基础,有基础的小伙伴应该知道,树本最常见的就是二叉树,存在二个孩子节点,有点类似我们二分的思想,所以学习好二分查找,理解二分思想非常重要
-
- 二分查找本身可以通过递归实现,也是成为了我们理解递归的重要基础,注意递归的思想,本身被更多的人认为是非常抽象的,但是递归本身是应用十分广泛
如何理解二分查找
- 二分查找一般由left、right、mid、target组成,正式它们组成了一个二分的重要过程
- 下面我们引入之前帖子中小朋友排好队的思路,我们目前假设队伍已经排好,我们要查找其中一个小朋友
- 首先,我们的left=0, right=data.lentgh-1, 此时mid=(left+rigth)/2;
- 当我们查看排在mid的小朋友的时候,出现了三种情况
-
- 要查找的小朋友恰好是mid的这个小朋友,这个时候查找成功,返回
-
- 要查找的小朋友在mid的左边,此时我们应该调整,rigth的边界值,取掉右边小朋友的范围,并且不包括mid的这个小朋友right=mid-1
-
- 要查找的小朋友在mid的右边,此时我们应该调整,left的边界值,取掉左边小朋友的范围,并且不包括mid的这个小朋友left=mid+1
-
- 如果我们没有查找,就在更小的一半范围内继续查找,此时我们还是执行了上述相同的问题,所以我们不难想象这是一个递归的过程
$\color{ff0000}{提醒:}$由于left+right可能会溢出,我们一般都是使用了right+(right-left)/2
替换,虽然这个优化不是特别大,但是其本身存在,更加合理,所以还是希望小伙伴们可以理解
什么是递归
有一个很递归很接近的兄弟,它是称为递推,一般地,我们在这样描述它们,递推是人,递归是神
- 其实递归本身,就是我们在数据范围更小的情况下,继续处理相同的问题,在这种情况下,代码量大大减少,所以递归本身就是一个边界条件的问题,当然在递归的时候,我们一般地把这个边界称为递归出口
- 而递推,就是在规律性地推出后面的结果,它是把一个复杂性地计算,演变成更多的简单过程
- 递归和递推希望小伙伴可以多多想想
二分查找的递归和非递归的实现代码实现
/**
* @Author Piwriw.
* @Date 2022/1/20
* @motto 你不能做我的诗,正如我不能做你的梦.
*/
public class BinarySearch {
private BinarySearch() {
}
public static <E extends Comparable<E>> int searchRe(E[] data, E target) {
return searchRe(data, 0, data.length - 1, target);
}
/**
* 递归的方式实现二分查找
*/
private static <E extends Comparable<E>> int searchRe(E[] data, int l, int r, E target) {
if (l > r) {
return -1;
}
int mid = l + (r - l) / 2;
if (data[mid].compareTo(target) == 0) {
return mid;
}
if (data[mid].compareTo(target) < 0) {
return searchRe(data, mid + 1, r, target);
}
return searchRe(data, l, mid - 1, target);
}
/**
* 非递归实现二分查找
*/
public static <E extends Comparable<E>> int search(E[] data,E target){
int l=0,r=data.length-1;
while (l<=r){
int mid=l+(r-l)/2;
if (data[mid].compareTo(target)==0){
return mid;
}
if (data[mid].compareTo(target)<0){
l=mid+1;
}
else{
r=mid-1;
}
}
return -1;
}
}
总结
- 其实本身二分查找,可以为很多知识学习的一些基础,我提到的递归和树都是这样,其实本身算法就是一种思想上,每种语言实现,都可能存在着差异,但是思想是万变不离其宗的:grin::grin::grin:
- 其实今天的二分查找还是一个最裸机的版本,二分查找本身,就如我提到的当我们查找的时候,我们不包含边界条件上的值,或者当我们多个值相同时候,我们又要如何处理,边界问题其实本身就有着很多的变形,本身也要根据具体而定,所以大家之后如果使用二分查找,要确定好边界条件,但是本身跟我们这个代码是大差不差的
- 今天的习题:
- 704. 二分查找 原始的二分实现
- 875. 爱吃香蕉的珂珂 需要我们对二分的边界条件作出修改
- 这里关于递归和递推我也想给出二道十分经典的问题:
- 剑指 Offer 10- I. 斐波那契数列
- 剑指 Offer 10- II. 青蛙跳台阶问题
- 以上的题目本身不难,但是我希望能通过练习来学到关于一些递归和递推的思想
- 这里是:春节不停更,此文正在参加「星光计划-春节更帖活动」,本人正在计划在这次活动中,跟大家分享一下,我学习数据结构与算法的心得,这是数据结构第四天的二分查找,这次的分享可能也要结束了,数据结构与算法本身可能在工作中实现业务功能没有那么中重要,但是作为编程的重要基础,本身也有着繁多的内容,但是更多的玩法,更多更好的实现和优化,更多的路还在各位脚下。:laughing::laughing::laughing:
©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
标签
赞
2
收藏
回复
相关推荐