(一)算法--查找算法顺序查找和二分查找(递归和非递归方式)


         我们抛开二分查找算法,如果有这样的一个需求,需要在一些数字中找出有没有某个数字,我们应该怎么做?



         1 首先我们会想到用什么数据结构存放这些数?


         数据结构就是计算机存储组织、组织数据的方式。可以这样理解,生活中我们穿的衣服需要放到一个地方,衣服可以放到衣橱中,也可以放到行李箱中,也可以放到衣架中,这里的衣架、衣橱、和行李箱及是衣服的存放结构。所以我们在查找某一个数字是否在一堆数字中的时候,我们要把数据放到数据结构中,不同的数据结构有不同的优势,就像衣服放到不同的“存储”中,会有不同的优势。而精心选择的数据结构可以带来更高的运行或者存储效率。



         计算机中有哪些数据结构呢?


         常见的数据结构有数组(Array)、堆栈(Stack)、队列(Queue)、链表(Linked List)、树(Tree)、图(Graph)、堆(Heap)、散列表(Hash)。


         具体的数据结构以及优势就不再这里介绍了,以后会一一介绍。

         而java语言常用的数据结构有数组,list,set,map。list实际上也是数组结构,不太复杂和确定长度下,使用数组的效率会高些,数组是确定长度的。list的值可以重复,set的值不可以重复,map是一种键值对,键可以是多种类型的与值形成对应关系。

         我们是在固定一些数字中查找到我们想要的数字所在位置,当我们需要存储或处理一系列数据,数组就可以充当这样的角色,它的内存是相连的数据,并且在栈中引用只有一个,如果不用数组,就要一个一个的声明,浪费存储空间,显然不合理,所以我们在这里用数组结构,而java的其他数据结构分别适合在哪些场景中使用呢?在这里就不介绍了,后续文章会总结。




         2  顺序查找


         抛开所学,我们最简单和最”笨”的方式就是挨个的查找和比较,看是不是我想要的那个key。这就是顺序查找。java代码如下

  条件:无序或有序元素。
  原理:按顺序比较每个元素,直到找到关键字为止。
  时间复杂度:O(n)

/**
     * 顺序查找
     * @param srcArray
     * @param key
     * @return
     */
    public static int orderSearch(int srcArray[],int key){
        for(int i=0;i<srcArray.length-1;i++){
            if(key == srcArray[i]){
                return i;
            }
        }
        return -1;
    }





         3 二分查找法


         当我们的数字是有序的情况下,可以采用顺序查找法,也可以采用二分查找法,而人们发现发了在元素有序的时候,使用二分查找法效率更高。大概是谁想出来的二分查找法的人物不再说明,说一下二分查找思想。

         条件:有序元素

         思想: 

         3.1 不像顺序查找那样,我们取得数组中间的数字,如果正好是我们要查找的元素,则搜索过程结束;

         3.2 中间的元素不是我们想要的元素,我们比较中间元素和我们想要元素的大小

         如果中间元素大于/小于中间元素,则我们在大于/小于的那一半查找,而且和开始一样从中间的元素开始比较(也就是把剩下的一半当做新的开始)。

         3.3 直到某一步比较,找到我们的key,返回该key所在的数组下标。

         3.4 如果都没有找到,存放数组低地址的变量大于高地址变量时,则查找结束,说明该有序序列中没有我们想找到的。

         复杂度:O(logn)


         解决问题思想到程序实现,这里面有几个点。

         1)取数组中间位置,第一次可以是数组元素长度/2,第二次我们如何从数组剩下的一半中取中间位置?以及第三次呢?也就是每次我们都要知道”新数组”的开始和结尾,以及中间位置;所以我们可以定义两个数组下标变量,low 和high(内存中的地址大小),以及mid(每次的中间下标),这样通过移动他们来做到轮询,有些类似c语言中的指针变量。

         2)怎么结束比较?每次都找不到,直到数组的一半已经没有元素了,也就是low指向的数组地址已经大于high指向的数组地址,说明不存在。java代码如下,之后再逐步分析代码


         非递归方式实现

 /**
     * 二分查找普通实现。
     * @param srcArray 有序数组
     * @param key 查找元素
     * @return  不存在返回-1,存在返回对应的数组下标
     */
    public static int binSearch(int srcArray[], int key) {
        int mid = srcArray.length / 2;
        if (key == srcArray[mid]) {
            return mid;
        }

        int low= 0;
        int high = srcArray.length - 1;
        while (low<= high) {
            mid = (high - low) / 2 + low;
            if (key < srcArray[mid]) {
                high = mid - 1;
            } else if (key > srcArray[mid]) {
                low = mid + 1;
            } else {
                return mid;
            }
        }
        return -1;
    }
         


           递归方式实现


 /**
     * 二分查找递归实现。
     * @param srcArray  有序数组
     * @param low 数组低地址下标
     * @param high   数组高地址下标
     * @param key  查找元素
     * @return 查找元素不存在返回-1,存在返回对应的数组下标
     */
    public static int binSearch(int srcArray[], int low, int high, int key) {
        int mid = (high  - low) / 2 + low;
        if (srcArray[mid] == key) {
            return mid;
        }
        if (low >= high) {
            return -1;
        } else if (key > srcArray[mid]) {
            return binSearch(srcArray, mid + 1, high, key);
        } else if (key < srcArray[mid]) {
            return binSearch(srcArray, low, mid - 1, key);
        }
        return -1;
    }

         

          main方法

 public static void main(String[] args) {
        int srcArray[] = {3,6,11,17,21,23,28,30,81,89,99};
        System.out.println(binSearch(srcArray, 0, srcArray.length - 1, 222));
        System.out.println(binSearch(srcArray,222));
        System.out.println(orderSearch(srcArray,5));
    }


         执行过程图,大概的画了一下,如下图。




         两种实现方式,一种是普通实现方式,一种是递归思想实现方式,递归关注一个核心,而把变化的部分通过递归变量的改变而变化。


         看了之前写过二分查找算法,但是过了一段时间发现又会忘记,是当时没有真正理解吧,之前的简单粗暴,也感谢网友们当时指出问题:         http://blog.csdn.net/lovesummerforever/article/details/24588989


        总结:

         知识一定要变成自己的理解,才是自己的,不然会是瞬时记忆,都会还给书本。

         2 孤立的知识很难被记住,我们想要成块的去理解,不要只学习其中的断层,知道学习这个技术在知识体系中的什么位置,和其他知识的联系。

         3 晦涩难懂的东西要追本溯源,因为这个技术一定是从简单演变而来的,是多个简单的叠加过程,最终我们才看到成型,必须要思考是怎么衍变的。(例如文字的发展史)


         4 技术来自生活却高于生活,当不懂的时候,想想生活中的一些离我们近的事物,都是如出一辙的。


  • 10
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值