• 72-Java的选择排序、二分查找、Lambda表达式


    一、选择排序

    1、选择排序的思想

    • 每轮选择当前位置,开始找后面的较小值与该位置进行交换。

      第一轮:选择当前位置,当前位置是5,所以5与1比较,大于1,所以5与1进行交换。
      在这里插入图片描述


      5与1交换后,1就在当前位置,因此,1与后面的所有值进行比较,后面的值都大于1,所以1的位置不变。
      在这里插入图片描述




      第二轮:选择当前位置,当前位置是5,所以5与3比较,大于3,所以5与3进行交换
      在这里插入图片描述


      5与3交换后,3就在当前位置,因此,3与后面的所有值进行比较,后面的2小于3,所以3与2进行交换
      在这里插入图片描述




      第三轮:选择当前位置,当前位置是5,所以5与3比较,大于3,所以5与3进行交换
      在这里插入图片描述





    2、选择排序的关键

    • 确定总共需要选择几轮:数组的长度 -1。

      • 比如:数组有5个元素,只需要比4轮,就可以排序完了。
    • 控制每轮从当前位置为基准,与后面元素选择几次。

    package com.app.d8_sort_binarysearch;
    
    import java.util.Arrays;
    
    /**
        目标:学会使用选择排序的方法,对数组进行排序
     */
    public class Demo1 {
        public static void main(String[] args) {
            // 1、定义数组,传入一组数据
            int[] numbers = {5, 1, 3, 2};
            //               0  1  2  3
    
            // 2、输出原数组内容
            System.out.println("排序前:" + Arrays.toString(numbers));
    
            // 3、定义外部for循环,控制选择几轮:数组长度 -1
            for (int i = 0; i < numbers.length -1; i++) {
                // i = 0    j = 1 2 3
                // i = 1    j = 2 3
                // i = 2    j = 3
                // 4、定义内部for循环,控制选择几次:当前位置 +1,也就是后一位
                for (int j = i+1; j < numbers.length; j++) {
                    // 当前位置:numbers[i]
                    // 5、如果后面有比当前位置更小的数据,则进行交换
                    if (numbers[j] < numbers[i]){
                        // 交换位置
                        // a、先定义一个临时变量将当前位置的数据存一下
                        int temp = numbers[i];
                        // b、再将后面的数据 赋值给 当前的位置
                        numbers[i] = numbers[j];
                        // c、最后将当前位置的数据 赋值给 后面的位置
                        numbers[j] = temp;
                    }
                }
            }
    
            // 6、全部交换完成,输出排序后的数组内容
            System.out.println("排序后:" + Arrays.toString(numbers));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    排序前:[5, 1, 3, 2]
    排序后:[1, 2, 3, 5]
    
    Process finished with exit code 0
    
    • 1
    • 2
    • 3
    • 4



    二、二分查找

    1、基本查找

    • 需求:

      • 我要查找数组中的3在哪个位置索引?
      • 如果是基本查找,就需要从第一个位置一个一个的往后找。
        在这里插入图片描述

    • 结论:在数据量特别大的时候,基本查找从前往后寻找的性能是很差的!!



    2、二分查找

    • 二分查找性能好,前提必须是排好序的数据
    • 二分查找相当于每次去掉一半的查找范围。
    找到元素的执行原理:
    • 需求:

      • 我要查找数组中的3在哪个位置索引?
        在这里插入图片描述

    • 二分查找会定一个位置在首,定一个位置在尾
      在这里插入图片描述


    • 之后会找,首和尾的一半的位置
      在这里插入图片描述


    • 然后,发现数据3 小于 首和尾一半位置的数据,直接从左边开始找,将右边干掉
      在这里插入图片描述


    • 因此,尾部的位置就是:一半的位置-1
      在这里插入图片描述


    • 然后,又找首和尾的一半的位置
      在这里插入图片描述


    • 之后,发现数据3 大于 首和尾一半位置的数据,直接从右边开始找,将左边干掉
      在这里插入图片描述


    • 然后,首部的位置就是:一半的位置 +1
      在这里插入图片描述


    • 最后,再找首和尾一半的位置,发现这个位置的数据刚好是3,因此将位置索引 2返回

    在这里插入图片描述



    找不到元素的执行原理:
    • 需求:

      • 我要查找数组中的11在哪个索引?
        在这里插入图片描述
    • 二分查找会定一个首位置和一个尾位置

    在这里插入图片描述


    • 然后,发现数据11 大于 首和尾一半位置的数据,直接从右边开始找,将左边干掉
      在这里插入图片描述


    • 之后,首位置就是:一半的位置 +1
      在这里插入图片描述


    • 然后,又找首和尾一半的位置(折半)
      在这里插入图片描述


    • 之后,发现数据11 大于 首和尾一半位置的数据,直接从右边开始找,将左边干掉
      在这里插入图片描述


    • 然后,首位置就是:一半的位置 +1
      在这里插入图片描述


    • 之后,又找首和尾一半的位置
      在这里插入图片描述


    • 然后,发现数据11 大于 首和尾一半位置的数据,直接从右边开始找,将左边干掉
      在这里插入图片描述


    • 此时,首位置就是:一半位置 +1,然后发现首尾位置重合了,因此,一半的位置还是自己,但是已经是最后一次查找了,数据还是不相等

      在这里插入图片描述


    • 结论:二分查找正常的检索条件应该是首位置min <= 尾位置max,但是现在是 !=,因此属于找不到,元素不存在



    package com.app.d8_sort_binarysearch;
    
    import java.util.Arrays;
    
    /**
        目标:理解二分查找其执行原理
     */
    public class Demo2 {
        public static void main(String[] args) {
            // 1、定义一个数组,传入一组数据
            int[] arr = {34, 23, 566, 78, 11, 35, 66, 99};
    
            // 2、二分查找的前提必须是排好序的数据,所以先排序
            Arrays.sort(arr);
    
            // 3、输出排序后的数组内容
            System.out.println("排序后:" + Arrays.toString(arr));
            // 排序后:[11, 23, 34, 35, 66, 78, 99, 566]
            // 		   0   1   2   3   4   5   6    7   -1
    
            // 5、调用二分查询的方法,查询要找的元素
            int index1 = binarySearch(arr, 66);
            int index2 = binarySearch(arr, 600);
    
            System.out.println("该元素的位置索引:" + index1);
            System.out.println("该元素的位置索引:" + index2);
    
            // 6、判断该元素是否存在:
            /*if (index > 0) {
                // a、索引位置 大于 0,说明存在,输出该元素的位置索引
                System.out.println("该元素的位置索引:" + index);
            }else {
                // c、索引位置 小于 0,说明不存在,提示查无此元素
                System.out.println("查无此元素!");
            }*/
        }
    
    
        /**
         * 4、二分查找算法的实现方法
         * @param arr       排序的数组
         * @param data      要找的数组元素
         * @return          如果元素存在,则返回元素的位置索引,否则返回-1。
         */
        public static int binarySearch(int[] arr, int data) {
            // a、定义首和尾的位置
            int head = 0;               // 首
            int tail = arr.length - 1;    // 尾
    
            // b、定义循环: 当首位置 <= 尾位置时,开始二分查询(折半)
            while (head <= tail) {
                // c、找首和尾位置的一半的位置(中间索引)
                int midIndex = (head + tail) / 2;   // 中间索引 = (首索引 - 尾索引) / 2;
    
                // d、当要找的元素 大于 中间索引位置的元素时:
                if (data > arr[midIndex]) {
                    // (1) 说明要找的元素在尾位置那边,更新首位置的索引 = 中间位置的索引 +1
                    head = midIndex + 1;
                }else if (data < arr[midIndex]){
                    // e、当要找的元素 小于 中间索引位置的元素时:
                    // (1) 说明要找的元素在首位置那边,更新尾位置的索引 = 中间位置的索引 -1
                    tail = midIndex - 1;
                }else {
                    // f、当要找的元素 等于 中间索引位置的元素时:
                    // (1) 说明要找的元素已经找到了,返回该元素的位置索引
                    return midIndex;
                }
            }
    
            // g、循环结束,说明仍然找不到要找的元素,因此查无此元素,返回-1
            return -1;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    排序后:[11, 23, 34, 35, 66, 78, 99, 566]
    该元素的位置索引:4
    该元素的位置索引:-1
    
    Process finished with exit code 0
    
    • 1
    • 2
    • 3
    • 4
    • 5



    总结

    1、数组的二分查找的实现步骤是什么?

    • 定义变量记录首和尾的位置
    • 使用while循环控制二分查询(条件是首位置 <= 尾位置)
    • 循环内部获取中间元素索引(中间元素的索引 = (首位置的索引 + 尾位置的索引) / 2)
    • 判断当前要找的元素如果大于中间位置的元素,首位置 = 中间索引 +1
    • 判断当前要找的元素如果小于中间位置的元素,首位置 = 中间索引 -1
    • 判断当要找的元素如果等于中间位置的元素,返回当前中间元素的索引
    • 循环结束,说明查无此元素!返回-1


    三、Lambda表达式

    1、Lambda是啥?

    • Lambda表达式是JDK8开始后的一种新语法形式。
    • 作用:简化匿名内部类的代码写法

    2、Lambda表达式的简化格式:

    (匿名内部类被重写方法的形参列表)->{
    	被重写方法的方法体代码;
    }
    
    • 1
    • 2
    • 3
    • 注意:->是语法形式,无实际含义
    • 注意:Lambda表达式只能简化函数式接口的匿名内部类的写法形式
      在这里插入图片描述

    3、函数式接口是啥?

    • 首先必须是接口,其次接口中有且仅有一个抽象方法的形式。
    • 通常我们会在接口上加上一个@FunctionalInterface注解,标记该接口必须是满足函数式接口。
    package com.app.d9_lambda;
    
    /**
        目标:学会使用Lambda表达式的标准格式简化匿名内部类的代码形式
     */
    public class LambdaDemo2 {
        public static void main(String[] args) {
    //         1、Lambda只能简化接口中只有一个抽象方法的匿名内部类形式
            // 匿名内部类形式
    //        Swimming s1 = new Swimming() {
    //            @Override
    //            public void swim() {
    //                System.out.println("运动员游得飞快~~~~~");
    //            }
    //        };
    //        go(s1);
    
            // 第一次简化:lambda表达式
            Swimming s2 = () -> {
                System.out.println("运动员游得飞快~~~~~");
            };
            go(s2);
    
    
            System.out.println("-------------------------");
    
            // 第二次简化:匿名内部类形式作为实参传入go方法
    //        go(new Swimming() {
    //            @Override
    //            public void swim() {
    //                System.out.println("学生游得很开心~~~~~");
    //            }
    //        });
    
            // 第三次简化:lambda表达式
            go(() -> {
                System.out.println("学生游得很开心~~~~~");
            });
        }
    
        public static void go(Swimming s){
            System.out.println("开始...");
            s.swim();
            System.out.println("结束...");
        }
    }
    
    @FunctionalInterface    // 一旦定义了这个注解,必须是函数式接口,且内部只能有一个抽象方法
    interface Swimming{
        void swim();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    开始...
    运动员游得飞快~~~~~
    结束...
    -------------------------
    开始...
    学生游得很开心~~~~~
    结束...
    
    Process finished with exit code 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9


    4、总结

    1、Lambda表达式的基本作用?

    • 简化函数式接口的匿名内部类的代码形式

    2、Lambda表达式有什么使用前提?

    • 必须是接口的匿名内部类,接口中只能有一个抽象方法

    3、Lambda表达式的好处?

    • Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码,它可以写出更简洁、更灵活的代码
    • 作为一种更紧凑的代码风格,使Java语言表达能力得到了提升



    5、Lambda实战-简化常见函数式接口

    (1) Lambda表达式简化Comparator接口的匿名内部类形式

    在这里插入图片描述



    (2) Lambda表达式简化按钮监听器ActionListener接口的匿名内部类形式

    在这里插入图片描述



    6、Lambda表达式的省略规则

    进一步在Lambda表达式的基础上继续简化

    • 参数类型可以省略不写
      在这里插入图片描述


    • 如果只有一个参数,参数类型可以省略,同时 () 也可以省略
      在这里插入图片描述


    • 如果Lambda表达式的方法体代码只有一行代码,可以省略 {} 不写,同时要省略 ;不写
      在这里插入图片描述


    • 如果Lambda表达式的方法体代码只有一行代码,可以省略 {} 不写。此时,如果这行代码是 return 语句,必须省略 return不写,同时也可以省略 ;不写
      在这里插入图片描述



    在这里插入图片描述

  • 相关阅读:
    python转yuyv422到jpg
    gitlab+jenkins+k8s实现持续集成springboot+springcloud
    【JVM】关于 JVM,你需要掌握这些 | 一文彻底吃透 JVM 系列
    UNet++详细解读(二)pytorch从头开始搭建UNet++
    强化学习从基础到进阶--案例与实践[7.1]:深度确定性策略梯度DDPG算法、双延迟深度确定性策略梯度TD3算法详解项目实战
    【接口测试】接口测试内容
    go pprof 你真用对了吗
    【代表团坐车】Python 实现-附ChatGPT解析
    教你几个手机识别图片中的文字小技巧
    共创软硬件协同生态:Graphcore IPU与百度飞桨的“联合提交”亮相MLPerf
  • 原文地址:https://blog.csdn.net/yelitoudu/article/details/126151960