数据结构与算法第四天 原创

发布于 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}{特别提醒,二分查找本身只能使用在有序的情况下,所以我们这里没有添加上我们排序的时间}$

为什么要学习二分查找

    1. 二分查找本身,首先运行效率达到了比较高的O(logn),这个级别运算效率足够快
    1. 二分查找本身我个人认为是理解之后的的重要基础,有基础的小伙伴应该知道,树本最常见的就是二叉树,存在二个孩子节点,有点类似我们二分的思想,所以学习好二分查找,理解二分思想非常重要
    1. 二分查找本身可以通过递归实现,也是成为了我们理解递归的重要基础,注意递归的思想,本身被更多的人认为是非常抽象的,但是递归本身是应用十分广泛

如何理解二分查找

  • 二分查找一般由left、right、mid、target组成,正式它们组成了一个二分的重要过程
  • 下面我们引入之前帖子中小朋友排好队的思路,我们目前假设队伍已经排好,我们要查找其中一个小朋友
    • 首先,我们的left=0right=data.lentgh-1, 此时mid=(left+rigth)/2;
    • 当我们查看排在mid的小朋友的时候,出现了三种情况
        1. 要查找的小朋友恰好是mid的这个小朋友,这个时候查找成功,返回
        1. 要查找的小朋友在mid的左边,此时我们应该调整,rigth的边界值,取掉右边小朋友的范围,并且不包括mid的这个小朋友right=mid-1
        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:
  • 其实今天的二分查找还是一个最裸机的版本,二分查找本身,就如我提到的当我们查找的时候,我们不包含边界条件上的值,或者当我们多个值相同时候,我们又要如何处理,边界问题其实本身就有着很多的变形,本身也要根据具体而定,所以大家之后如果使用二分查找,要确定好边界条件,但是本身跟我们这个代码是大差不差的
  • 今天的习题:
  • 这里是:春节不停更,此文正在参加「星光计划-春节更帖活动」,本人正在计划在这次活动中,跟大家分享一下,我学习数据结构与算法的心得,这是数据结构第四天的二分查找,这次的分享可能也要结束了,数据结构与算法本身可能在工作中实现业务功能没有那么中重要,但是作为编程的重要基础,本身也有着繁多的内容,但是更多的玩法,更多更好的实现和优化,更多的路还在各位脚下。:laughing::laughing::laughing:

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
2
收藏
回复
举报
回复
添加资源
添加资源将有机会获得更多曝光,你也可以直接关联已上传资源 去关联
    相关推荐