Java学习笔记===》12.常见算法和Lambda表达式

常见算法和 Lambda

导学:企业中常见的算法

1.地图的路线选择

2.满减活动的算法问题

3.运动app的计步功能

4.短视频的个性推荐功能

1.常见算法

(1)查找算法

①基本查找

在一堆数据中查找某个数据是否存在

步骤:

先将数据放入容器当中,这个容器可以是数组、集合等,然后根据索引进行查找

package com_05_DataStructure._01BasicSeaqrch;

public class BasicSearch_test01 {
    public static void main(String[] args) {
        //基本查找
        //核心:从0索引开始诶个往后查找,所以也叫顺序查找

        //需求:定义一个方法利用基本查找,查找某个元素是否存在
        //数据{131,127,147,81,103,23,7,79}
        int [] arr = {131,127,147,81,103,23,7,79};
        boolean result = search(arr, 79);
        System.out.println(result);
    }

    public static boolean search(int [] arr,int num){
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == (num)){
                return true;
            }
        }
        return false;
    }
}

练习

package com_05_DataStructure._01BasicSeaqrch;

import java.util.ArrayList;

public class BasicSearch_test02 {
    public static void main(String[] args) {
        //课堂练习1:
        //需求:定义一个方法利用基本查找,查询某个元素在数组中的索引
        //要求:不需要考虑数组中元素是否重复


        //课堂练习2:
        //需求:定义一个方法利用基本查找,查询某个元素在数组中的索引
        //要求:需要考虑数组中元素有重复的可能性
        //{131, 127, 147, 81, 103, 23, 7, 79, 81}
        //我要查找81,想要返回的是所有索引 3 8

        int [] arr = {131, 127, 147, 81, 103, 23, 7, 79, 81};
        int  result2 = search2(arr, 81);
        System.out.println(result2);
    }
    public static int search2(int [] arr,int num){
        while (true){
            for (int i = 0; i < arr.length; i++) {
                if (arr[i] != num){

                }else{
                    return i;

                }
            }
        }
    }
    public static ArrayList<Integer> search(int[]arr, int num){
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == num){
                list.add(i);
            }
        }
       return list;
    }


}

②二分查找/折半查找

前提条件:容器中的数据必须是有序的

核心逻辑:每次排除一半的查找范围

1.创建一个最小索引min和一个最大索引max

2.mid是在min和max中间的

3.如果要查找的元素在mid的左边,缩小范围时,min不变,max = mid - 1

4.如果要查找的元素在mid的右边,缩小范围时,max不变,min = mid + 1

说明:元素必须是有序的,从小到大,或者从大到小都是可以的。

如果是无序的,也可以先进行排序。但是排序之后,会改变原有数据的顺序,查找出来元素位置跟原来的元素可能是不一样的,所以排序之后再查找只能判断当前数据是否在容器当中,返回的索引无实际的意义。

基本思想:也称为是折半查找,属于有序查找算法。用给定值先与中间结点比较。比较完之后有三种情况:

  • 相等

    说明找到了

  • 要查找的数据比中间节点小

    说明要查找的数字在中间节点左边

  • 要查找的数据比中间节点大

    说明要查找的数字在中间节点右边

package com_05_DataStructure._02MiddleSearch;

public class BinarySearch_test01 {
    public static void main(String[] args) {
        //二分查找/折半查找
        //核心:
        //每次排除一半的查找范围

        //需求:定义一个方法利用二分查找,查询某个元素在数组中的索引
        //数据如下:{7, 23, 79, 81, 103, 127, 131, 147}
        int [] arr = {7, 23, 79, 81, 103, 127, 131, 147};
        int mid = search(arr, 127);
        System.out.println(mid);
        for (int i = 0; i < arr.length; i++) {
            
        }

    }
    
    public static int search(int []arr,int num){
        //1,定义两个变量记录要查找的范围
        int min = 0;
        int max = arr.length-1;
        //2.利用循环不断地去查找所需数据
        while (true){
            if (min>max){
                System.out.println("要查找的数据不在此数组中");
                return -1;
            }
            //找min和max中间位置
            int mid = (min+max)/2;

            //4.拿着mid指向的元素跟要查找的元素进行比较
            if(arr[mid] > num){
                //4.1 number在mid的左边
                //min不变,max = mid - 1;
                max = mid - 1;
            }else if(arr[mid] < num){
                //4.2 number在mid的右边
                //max不变,min = mid + 1;
                min = mid + 1;
            }else{
                //4.3 number跟mid指向的元素一样
                //找到了
                return mid;
            }
        }
    }
}
1>二分查找的优势

★提高查找效率

2>二分查找的前提条件

★容器中的数据必须是有序排列的

★如果数据是乱的,先排序再用二分查找得到的索引没有实际意义,只能确定当前数字在数组中是否存在,因为排序之后数字的位置就可能发生变化了

3>二分查找的过程

★定义两个变量min和max表示当前要查找的范围

★定义变量mid表示min和max的中间位置

★如果要查找的元素在mid的左边,缩小范围时,min不变,max = mid - 1

★如果要查找的元素在mid的右边,缩小范围时,max不变,min = mid + 1

< ★ >二分查找改进
1>插值查找

在介绍插值查找之前,先考虑一个问题:

​ 为什么二分查找算法一定要是折半,而不是折四分之一或者折更多呢?

其实就是因为方便,简单,但是如果我能在二分查找的基础上,让中间的mid点,尽可能靠近想要查找的元素,那不就能提高查找的效率了吗?

二分查找中查找点计算如下:

mid=(low+high)/2, 即mid=low+1/2*(high-low);

我们可以将查找的点改进为如下:

mid=low+(key-a[low])/(a[high]-a[low])*(high-low),

这样,让mid值的变化更靠近关键字key,这样也就间接地减少了比较次数。

基本思想:基于二分查找算法,将查找点的选择改进为自适应选择,可以提高查找效率。当然,差值查找也属于有序查找。

**细节:**对于表长较大,而关键字分布又比较均匀的查找表来说,插值查找算法的平均性能比折半查找要好的多。反之,数组中如果分布非常不均匀,那么插值查找未必是很合适的选择。

代码跟二分查找类似,只要修改一下mid的计算方式即可。

2>斐波那契查找

在介绍斐波那契查找算法之前,我们先介绍一下很它紧密相连并且大家都熟知的一个概念——黄金分割。

黄金比例又称黄金分割,是指事物各部分间一定的数学比例关系,即将整体一分为二,较大部分与较小部分之比等于整体与较大部分之比,其比值约为1:0.618或1.618:1。

0.618被公认为最具有审美意义的比例数字,这个数值的作用不仅仅体现在诸如绘画、雕塑、音乐、建筑等艺术领域,而且在管理、工程设计等方面也有着不可忽视的作用。因此被称为黄金分割。

在数学中有一个非常有名的数学规律:斐波那契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89…….

(从第三个数开始,后边每一个数都是前两个数的和)。

然后我们会发现,随着斐波那契数列的递增,前后两个数的比值会越来越接近0.618,利用这个特性,我们就可以将黄金比例运用到查找技术中。

Java学习笔记===》12.常见算法和Lambda表达式_第1张图片

基本思想:也是二分查找的一种提升算法,通过运用黄金比例的概念在数列中选择查找点进行查找,提高查找效率。同样地,斐波那契查找也属于一种有序查找算法。

斐波那契查找也是在二分查找的基础上进行了优化,优化中间点mid的计算方式即可

public class FeiBoSearchDemo {
    public static int maxSize = 20;

public static void main(String[] args) {
    int[] arr = {1, 8, 10, 89, 1000, 1234};
    System.out.println(search(arr, 1234));
}

public static int[] getFeiBo() {
    int[] arr = new int[maxSize];
    arr[0] = 1;
    arr[1] = 1;
    for (int i = 2; i < maxSize; i++) {
        arr[i] = arr[i - 1] + arr[i - 2];
    }
    return arr;
}

public static int search(int[] arr, int key) {
    int low = 0;
    int high = arr.length - 1;
    //表示斐波那契数分割数的下标值
    int index = 0;
    int mid = 0;
    //调用斐波那契数列
    int[] f = getFeiBo();
    //获取斐波那契分割数值的下标
    while (high > (f[index] - 1)) {
        index++;
    }
    //因为f[k]值可能大于a的长度,因此需要使用Arrays工具类,构造一个新法数组,并指向temp[],不足的部分会使用0补齐
    int[] temp = Arrays.copyOf(arr, f[index]);
    //实际需要使用arr数组的最后一个数来填充不足的部分
    for (int i = high + 1; i < temp.length; i++) {
        temp[i] = arr[high];
    }
    //使用while循环处理,找到key值
    while (low <= high) {
        mid = low + f[index - 1] - 1;
        if (key < temp[mid]) {//向数组的前面部分进行查找
            high = mid - 1;
            /*
              对k--进行理解
              1.全部元素=前面的元素+后面的元素
              2.f[k]=k[k-1]+f[k-2]
              因为前面有k-1个元素没所以可以继续分为f[k-1]=f[k-2]+f[k-3]
              即在f[k-1]的前面继续查找k--
              即下次循环,mid=f[k-1-1]-1
             */
            index--;
        } else if (key > temp[mid]) {//向数组的后面的部分进行查找
            low = mid + 1;
            index -= 2;
        } else {//找到了
            //需要确定返回的是哪个下标
            if (mid <= high) {
                return mid;
            } else {
                return high;
            }
        }
    }
    return -1;
}
}

小结:

1.二分查找、插值查找,斐波那契查找各自的特点

★相同点:

​ 都是通过不断的缩小范围来查找对应数值的

★不同点

​ 计算mid的方式不一样

​ ★ 二分查找:mid每次 都是指向范围的中间位置

​ ★插值查找:mid尽可能的要靠近要查找的数据,但是要求数据尽可能的分布均匀

​ ★斐波那契查找:根据黄金分割点来计算mid指向的位置

③分块查找

1.分块原则

(1)前一块中的最大数据,小于后一块中所有的数据(块内无序,块间有序)

(2)块数的数量一般等于数字的个数开根号,比如,16个数字一般分为四块左右

2.核心思路;

先确定要查找的元素在哪一块,然后在块内挨个查找

3.查找步骤:

(1)创建数组blockArr存放每一个块对象的信息
(2)先查找blockArr确定要查找的数据属于哪一块
(3)再单独遍历这一块数据即可

package com_05_DataStructure._03BlockSearch;

public class BlockSearch_Test01 {
    public static void main(String[] args) {
        /*
            分块查找
            核心思想:
                块内无序,块间有序
            实现步骤:
                1.创建数组blockArr存放每一个块对象的信息
                2.先查找blockArr确定要查找的数据属于哪一块
                3.再单独遍历这一块数据即可
        */

        //1.将数据按照大致规律进行均匀分块
        int[] arr = {16, 5, 9, 12, 21, 18,
                32, 23, 37, 26, 45, 34,
                50, 48, 61, 52, 73, 66};

        //2.创建3个块的对象
        Block b1 = new Block(21,0,5);
        Block b2 = new Block(45,6,11);
        Block b3 = new Block(73,12,17);

        //3.定义数组用来管理三个块的对象(索引表)
        Block [] brr = {b1,b2,b3};

        //4.定义一个变量用来记录要查找的元素
        int num = 26;

        //5.调用方啊,传递索引表,数组,要查找的元素
        int index = getBlock(brr,arr,num);

        //打印索引
        System.out.println("要查找的元素在第"+(index+1)+"位,索引为"+index);

    }

    //利用分块查找的原理,查询number的索引
    //1.确定num在索引表的位置
    private static int getBlock(Block[] brr, int[] arr, int num) {
        //1.确定了要查找的数据在哪一块中
        int indexWhere = where(brr, 45);
        //2.利用基本查找找要查找的数据的具体位置
        if (indexWhere == -1){
            System.out.println("你要查找的数据不存在");
        }
        //执行到这里说明要查找的数据在数组里面
        //2.获取这一块的起始索引和结束索引
        int startIndex = brr[indexWhere].getStartIndex();
        int endIndex = brr[indexWhere].getEndIndex();
        for (int i = startIndex; i <= endIndex; i++) {
            if (arr[i] == num){
                return i;
            }
        }
        return -1;
    }


    //,定义方法,用来确定要查找的数据在哪个块里面
    public static int where (Block[] brr, int num){
        //2.创建3个块的对象
        //从0索引开始遍历Block,如果num小于块里的max,那么就表示num就在这一块
        for (int i = 0; i < brr.length; i++) {
            if (num <= brr[i].getMax()){
                return i;
            }
        }
        return -1;
    }
}


class Block{
    private int max;
    private int startIndex;
    private int endIndex;

    public Block() {
    }

    public Block(int max, int startIndex, int endIndex) {
        this.max = max;
        this.startIndex = startIndex;
        this.endIndex = endIndex;
    }

    public int getMax() {
        return max;
    }

    public void setMax(int max) {
        this.max = max;
    }

    public int getStartIndex() {
        return startIndex;
    }

    public void setStartIndex(int startIndex) {
        this.startIndex = startIndex;
    }

    public int getEndIndex() {
        return endIndex;
    }

    public void setEndIndex(int endIndex) {
        this.endIndex = endIndex;
    }
}

④扩展(扩展的分块查找==》无规律的数据)

3>树表查找
4>哈希查找

(2)排序算法

①冒泡排序(一般是从小到大排序)

<1>规则:

1.相邻的数据两两比较,小的放前面,大的放后面

2.在第一轮比较结束之后,最大的值已经找到,放到最右边

3.第二轮只要在剩余的元素找到最大值就可以了

4.每二轮循环结束,次大值已经确定,第三轮循环继续在剩余的数据中循环

<2>核心思想:

1.相邻的元素两两比较奥,大的放右边,小的放左边

2.第一轮比较完毕之后,最大值已经确定,第二轮可以少循环一次,后面以此类推

3.如果数组中有n和数据,总共我们只要执行n-q轮的代码就可以

package com_05_DataStructure._04Sort;

public class BubbleSort_Test01 {
    public static void main(String[] args) {
        /*
        冒泡排序===》核心思想
        1.相邻的元素两两比较奥,大的放右边,小的放左边
        2.第一轮比较完毕之后,最大值已经确定,第二轮可以少循环一次,后面以此类推
        3.如果数组中有n和数据,总共我们只要执行n-q轮的代码就可以
         */

        //1.定义一个数组
        int []arr = {3,6,5,7,8,34,2,65,54,23,46,45,62,67,63};

        //2.将数组中的元素按照从小到大的顺序排列
        int[] sort = BubbleSort(arr);
        for (int i = 0; i < sort.length; i++) {
            System.out.print(sort[i]+" ");
        }
    }

    public static int[] BubbleSort(int []arr){
        //外循环,表示我要执行多少轮,如果有n个数据,就要执行n-1轮
        for (int i = 0; i < arr.length-1; i++) {
            //内循环:表示每一轮我如何比较数据并找到当前的最大值
            //-1:为了防止索引越界
            //-i:提高效率,每一轮执行的次数都应该比上一轮-1
            for (int j = 0; j < arr.length-1-i; j++) {
                //i:依次表示数组中的每一个索引
                if (arr[j]>arr[j+1]){
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
        return arr;
    }
}

②选择排序

<1>规则以及核心思想

1.从0索引开始,拿着每一个索引上的元素跟后面的元素依次比较,

2.小的放前面,大的放后面。以此类推

3.每一轮循环结束后,最小的数据已经确定,排在第一位

4.第二轮循环索引从1开始以此类推

5.第三轮循环从2开始一次类推

package com_05_DataStructure._04Sort.SelectSort;

public class SelectSort_Test01 {
    public static void main(String[] args) {
        /*
            选择排序:
                1,从0索引开始,跟后面的元素一一比较。
                2,小的放前面,大的放后面。
                3,第一次循环结束后,最小的数据已经确定。
                4,第二次循环从1索引开始以此类推。

         */
        //1.定义一个数组
        int []arr = {3,6,5,7,8,34,2,65,54,23,46,45,62,67,63};

        //2.将数组中的元素按照从小到大的顺序排列
        int[] sort = SelectSort(arr);
        for (int i = 0; i < sort.length; i++) {
            System.out.print(sort[i]+" ");
        }

    }
    public static int[] SelectSort(int [] arr){
        //外循环:几轮
        //i:表示这一轮中,我拿着哪个索引上的数据跟后面的数据进行比较并交换
        for (int i = 0; i < arr.length -1; i++) {
            //内循环:每一轮我要干什么事情?
            //拿着i跟i后面的数据进行比较交换
            for (int j = i + 1; j < arr.length; j++) {
                if(arr[i] > arr[j]){
                    int temp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = temp;
                }
            }
        }
        return arr;
    }
}

③插入排序

★核心思想:

将0索引的元素到N索引的元素,看成是有序的,将N+1的元素到最后一个元素看成是无序的

遍历无序的元素,将遍历的元素插入有序序列中适当的位置,如遇到相同的元素,直接插到后面

N的范围:0 - 最大索引

package com_05_DataStructure._04Sort._03insertSort;

public class InsertSort_Test01 {
    public static void main(String[] args) {
        /*
      ★核心思想:
      将0索引的元素到N索引的元素,看成是有序的,将N+1的元素到最后一个元素看成是无序的
      遍历无序的元素,将遍历的元素插入有序序列中适当的位置,如遇到相同的元素,直接插到后面
      N的范围:0 - 最大索引
         */

        int[] arr = {3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48};




        //1.找到无序的那一组数据是从哪一个索引开始的
        int startIndex = -1;
        for(int i = 0;i<=arr.lrngth;i++ ){
            if(arr[i]>arr[i+1]){
                System.out.println(i+1);
                break;
            }
        }

        //2.遍历从startIndex开始到最后一个元素,依次得到无序序列中的每一个元素
        for (int i = startIndex; i < arr.length; i++) {
            //问题:如何吧遍历到的数据插入到有序序列中

            //记录当前要插入数据的索引
            int  j = i;

            while (j>0 && arr[j] <arr[j-1]){
                //交换位置
                int temp = arr[j];
                arr[j] = arr[j-1];
                arr[j-1] = temp;
                j--;
            }

        }

        printArr(arr);
    }

    private static void printArr(int[] arr) {
        //3.遍历数组
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }

}

④递归算法

1.递归算法

递归:指的是在方法中再去调用方法本身的现象

package com_05_DataStructure._04Sort._04quickSort;

public class digui {
    public static void main(String[] args) {

    }
    public static void method(){
        method();
    }
}

但是直接这么写会报错(内存溢出)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-186FISx0-1686128691912)(D:\java笔记\笔记图片\递归算法.png)]

会一直重复调用method方法,导致内存溢出

★注意:为了放置内存溢出,在写递归算法的时候,一定要有出口

(1)递归算法的作用

把一个复杂的问题层层转化位一个与原问题相似的规模较小的问题来求解(大事化小,小事化了)

(2)书写递归的两个核心

★找出口:什么时候不在调用方法

★找规则:如何把大问题变成规模较小的问题

练习

需求:求1-100之间的和

package com_05_DataStructure._04Sort._04quickSort;

public class diguiTest2 {
    public static void main(String[] args) {
        //需求:利用递归求1-100之间的和
        //100 + 99 + 98 + 97 + 96 + 95 .... + 2 + 1

        //大问题拆解成小问题
        //1~100之间的和 = 100 + (1~99之间的和)
        //1~99之间的和 = 99 + (1~98之间的和)
        //1~98之间的和 = 98 + (1~97之间的和)
        //。。。
        //1~2之间的和 = 2 + (1~1之间的和)
        //1~1之间的和 = 1(递归的出口)

        //核心:
        //1.找出口
        //2.找规律

        System.out.println(getSum(100));
    }


    public static int getSum(int number){
        //递归算法的出口,当number= 1的时候,
        if (number == 1){
            return 1;
        }
        //不等于1的时候
        return number + getSum(number-1);
    }
}

练习2:递归求阶乘

需求:用递归求5的阶乘,,并把结果在控制台输出

package com_05_DataStructure._04Sort._04quickSort;

public class diguiTest3 {
    public static void main(String[] args) {
        //需求:利用递归求5的阶乘
        //5! = 5 * 4 * 3 * 2 * 1;

        //核心:
        //1.找出口
        //2.找规律
        //心得:
        //方法内部再次调用方法的时候,参数必须要更加的靠近出口
        //第一次调用:5
        //第二次调用:4

        //5! = 5 * 4!;
        //4! = 4 * 3!;
        //3! = 3 * 2!;
        //2! = 2 * 1!;
        //1! = 1;
        System.out.println(jiecheng(5));
    }
    public static int jiecheng(int number){
        if (number == 1){
            return 1;
        }
        return  number * jiecheng(number -1);
    }
}

Java学习笔记===》12.常见算法和Lambda表达式_第2张图片

⑤快速排序

第一轮:把0索引的数字作为基准数,确定基准数在数组中的正确位置

====》第一轮结束之后,比基准数小的全在左边,笔基准数大的全在右边,后面以此类推

步骤:

1.先定义两个指向start和end(start表示0索引开始,end表示从末尾索引开始)

2.先移动end,找到比基准数小的元素,再移动start,找到比基准数大的元素

3.将start和end指向的元素进行位置交换

4.直至start和end指向的是同一个元素,将基准数和start或end指向的元素位置进行交换

5.然后将基准数左边的数据看成是一组,基准数右边的看成是一组,分别进行1,2,3,4步骤

注意:只能先从end开始找比基准数小的元素,否则会把比基准数大的元素放大基准数的前面,排序会出现错误

package com_05_DataStructure._04Sort._04quickSort;

public class quickSort {
    public static void main(String[] args) {
        /*
        快速排序:
            第一轮:以0索引的数字为基准数,确定基准数在数组中正确的位置。
            比基准数小的全部在左边,比基准数大的全部在右边。
            后面以此类推。
      */

        int[] arr = {1,1, 6, 2, 7, 9, 3, 4, 5, 1,10, 8};
        quickSort(arr,0,arr.length-1);
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]+", ");
        }

    }


    //参数一:我们要排序的数组
    //参数二:要排序数组的其实索引
    //参数三:要排序数组的结束索引
    public static void quickSort(int[]arr,int i,int j){
        //定义两个变量记录要查找的范围
        int start = i;
        int end = j;

        if (start > end){
            //递归的出口
            return;
        }

        //定义一个变量记录基准数
        int baseNumber = arr[i];

        //利用循环找到要交换的数字
        while (start != end){
            //利用end从后往前找比基准数小的数字
            while(true){
                if (end<=start || arr[end] < baseNumber){
                    break;
                }
                end--;
            }
            //利用start从前往后寻找,找到比基准数大的数字
            while(true){
                if (end<=start || arr[start] > baseNumber){
                    break;
                }
                start++;
            }
            //把end和start指向的元素进行交换
            int temp = arr[end];
            arr[end] = arr[start];
            arr[start] = temp;

        }

        //当start和end指向同一个元素时,那么上面的循环就会结束
        //表示已经找到了基准数在数组中存在的位置

        //基准数归位
        int mid = arr[i];
        arr[i] = arr[start];
        arr[start] = mid;

        quickSort(arr,i,start-1);
        quickSort(arr,start+1,j);

    }
}

⑥总结

1.冒泡排序

相邻的元素两两比较,小的放前面,大的放后面

2.选择排序

从0索引开始,拿着每一个索引山东个元素跟后面的元素依次比较,小的放前面,大的放后面

3.插入排序

将数组分为有序和无序两组,遍历无序数组,将元素插入有序序列即可

4.快速排序

★将排序范围中的第一个数字作为基准数,再定义两个变量start,end

★start从前往后找比基准数大的,end从后往前找比基准数小的

★找到之后交换start和end指向的元素,并循环这一过程,直到start和end指向同一个元素,该位置时基准数在数组中的位置,再让基准数归位

★归位后的效果:基准数左边的比基准数小,基准数右边的,比基准数大

2.Arrays

操作数组的工具类

方法名 说明
public static String toString(数组) 把数组拼接成一个字符串
public static int binarySearch(数组,数组元素) 二分查找法查找元素
public static int[] copyOf(原数组,新数组长度) 拷贝数组
public static int [] copyOfRange(原数组,起始索引,结束索引) 拷贝数组(指定范围)
public static void fill(数组,元素) 填充数组
public static void sort(数组) 按照默认方式进行数组排序
public static void sort(数组,排序规则) 按照指定的规则排序
package com_05_DataStructure._05Arrays;

import java.util.Arrays;

public class ArraysTest01 {
    public static void main(String[] args) {
        /*
操作数组的工具类
| 方法名                                                       | 说明                     |
| :----------------------------------------------------------- | :----------------------- |
| public static String toString(数组)                          | 把数组拼接成一个字符串   |
| public static int binarySearch(数组,数组元素)               | 二分查找法查找元素       |
| public static int[] copyOf(原数组,新数组长度)               | 拷贝数组                 |
| public static int [] copyOfRange(原数组,起始索引,结束索引) | 拷贝数组(指定范围)     |
| public static void fill(数组,元素)                          | 填充数组                 |
| public static void sort(数组)                                | 按照默认方式进行数组排序 |
| public static void sort(数组,排序规则)                      | 按照指定的规则排序       |
*/

        //1.toString :将数组变成字符串
        System.out.println("-------------------toString----------------------");
        int [] arr = {1,2,3,4,5,6,7,8,9,10};
        String s = Arrays.toString(arr);
        System.out.println(s);

        //2.inarySaearch: 二分查找法查找元素(结果是元素所在的索引)
        //细节1:二分查找的前提:数组中的元素必须是有序的,而且数组中的元素必须是升序的
        //细节2,如果查找的元素是存在的,那么返回的是真实的索引
        //      如果查找的元素是不存在的,那么返回的是  -插入点-1
        //插入点:要查找的元素
        //疑问:为什么要减1
        //解释:如果此时,要查找数字0,那么如果返沪的是 -插入点,就会出现问题了
        //如果要查找数字0,此时0是不存在的,但是按照上面的规则 -插入点,就应该是-0
        //为了避免这样的情况,Java在这个基础上-1
        System.out.println("-------------------binarySearch----------------------");
        int i1 = Arrays.binarySearch(arr, 6);  //5
        int i2 = Arrays.binarySearch(arr, 10);  //9
        int i3 = Arrays.binarySearch(arr, 20);  //-11
        System.out.println(i1);
        System.out.println(i2);
        System.out.println(i3);

        //3.copyOf(老数组,新数组的长度):拷贝数组
        //方法的底层会根据第二个参数来创建新的数组
        System.out.println("-------------------copyOf----------------------");
        //如果新数组的长度是小于老数组的长度,会部分拷贝
        int[] newArr1 = Arrays.copyOf(arr, arr.length-4);
        //如果新数组的长度是等于老数组的长度,那么会全部由拷贝
        int[] newArr2 = Arrays.copyOf(arr, arr.length);
        int[] newArr3 = Arrays.copyOf(arr, arr.length+6);
        //如果新数组的长度是大于老数组的长度,那么会补上默认初始化值

        printArr(newArr1);
        printArr(newArr2);
        printArr(newArr3);


        //4.copyOfRange:指定范围内拷贝数组
        //细节:包头不包围,包左不包右
        System.out.println("-------------------copyOfRange----------------------");
        int[] newArr4 = Arrays.copyOfRange(arr, 3, 7);//包含3索引,不包含7索引
        printArr(newArr4);

        //5.fill : 填充数组
        System.out.println("-------------------fill----------------------");
        Arrays.fill(arr,111);
        printArr(arr);

        //6.sort:给数组进行排序
        //细节:默认情况下,给基本数据类型进行升序排列,底层使用的是快速排序
        System.out.println("-------------------sort----------------------");
        Arrays.sort(newArr1);
        printArr(newArr1);


    }
    public static void printArr(int[] arr){
        System.out.println(Arrays.toString(arr));
    }
}
package com_05_DataStructure._05Arrays;

import java.util.Arrays;
import java.util.Comparator;

public class ArraysTest02  {
    public static void main(String[] args) {
        /*
        * public static void sort(数组,排序规则)  按照指定的规则进行排序
        * 参数一:要排序的数组
        * 参数二:排序的规则
        *细节:
        * 只能给引用数据类型的数组进行排序
        * 如果数组是基本数据类型的,需要变成其对应的包装类
        */

        Integer [] arr = {4,6,2,5,8,9,4,7,9,43,53,0};
        //其中第二个参数是一个接口,所以我们在调用方法的时候,需要传递这个接口的实现类对象,作为排序的规则
        //但是这个实现类,我们只需要使用一次,所以就没有比u要去单独写一个类,直接采取匿名内部类的方式就可以了

        //底层原理:
        //利用插入排序+二分查找的方式进行排序的
        //默认把0索引的数据当作是有序的序列,1索引到最后是无序的序列
        //遍历无序的序列得到里面的每一个元素,假设当前便利的到的元素是A
        //把A往有序序列中进行插入,再插入的时候,利用二分查找确定A元素的插入点
        //拿着A元素,个别插入点的元素进行比较,比较的规则就是compare方法的方法体
        //如果方法的返回值是负数,拿着A继续跟前面的数据进行比较
        //如果方法的返回值是正数,拿着A继续跟后面的数据进行比较
        //如果方法的返回值是0,也会拿着A跟后满的数据进行比较
        //直到能确定A的最终位置为止

        //compare方法的形式参数
        //参数一 o1:表示在无序序列中,得到的每一个元素
        //参数二 o2:表示有序序列中的元素


        //返回值
        //负数:表示当前要插入的元素是小的,要放在前面
        //正数:表示当前要插入的元素是大的,要放在后面
        //0:表示当前要插入的雅安苏跟现在的元素是一样的,也要放在后面


        //简单理解:
        // o1-o2  : 升序排列
        // o2-o1 : 降序排列
        Arrays.sort(arr, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println("-------------------------");
                System.out.println("o1:"+o1);
                System.out.println("o2:"+o2);
                return o1-o2;
            }
        });

        System.out.println(Arrays.toString(arr));
    }


}

3.Lambda表达式

1.函数式编程

​ 函数式编程(Functional progeamming)是一种思想特点

​ 函数式编程思想,忽略卖你想对象的复杂语法,强调做什么,而不是谁去做(更加关注方法体中的逻辑)

2.lambda表达式

​ lambda表达式是JDK8开始后的一种新语法形式

(1)lambda表达式的标准格式
() ->{
    
}

★()  对应着方法的形参
★ ->  lambda表达式的固定格式(没有特殊含义)
★()  对应着方法的方法体
(2)方法体改写的细节

★Lambda表达式可以用来简化匿名内部类的书写

★Lambda表达式只能简化函数式接口的匿名内部类的写法

★函数式接口:有且只有一个抽象方法的接口叫做函数式接口,接口上方可以降价@FunctionalInterface注解

package com_05_DataStructure._06lambda;

public class LambdaTest0 {
    public static void main(String[] args) {
/*
方法体改写的细节
★Lambda表达式可以用来简化匿名内部类的书写
★Lambda表达式只能简化函数式接口的匿名内部类的写法
★函数式接口:有且只有一个抽象方法的接口叫做函数式接口,接口上方可以降价@FunctionalInterface注解
*/
        //1.利用匿名内部类的形式去调用下面的方法
        //调用一个方法的时候,如果方法的形参是一个接口,那么我们要传递这个接口的实现类对象
        //弱国实现类对象只要用到一次,就可以用匿名内部类的形式进行书写

        //不适用lambda表达式
        method(new Swim() {
            @Override
            public void swimming() {
                System.out.println("Swimming");
            }
        });


        //2.利用Lambda表达式调用方法
        method(
                ()->{
                    System.out.println("Swimming");
                }
        );
    }

    public static void method(Swim s){
		s.swimming;
    }

    @FunctionalInterface
    interface Swim{
        public abstract void swimming();
    }
}
(3)小结
①Lambda表达式的基本作用

​ 简化函数式接口的内部匿名类的写法

②Lambda表达式的使用前提

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

③Lambda表达式的好处

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

(4)Lambda表达式的省略写法

★省略核心:可以推逃出来的代码,就可以省略

①参数类型可以省略

②如果只有一个参数,参数类型可以省略,同时()可以省略

③如果Lambda表达式的方法体只有一行,大括号,分号,return可以省略不写,需要同时省略

package com_05_DataStructure._06lambda;

import java.util.Arrays;
import java.util.Comparator;

public class LambdaTest02 {
    public static void main(String[] args) {
/*
Lambda的省略规则
1.参数类型可以省略不屑
2.如果只有一个参数,参数类型可以省略,同时()可以省略
3.如果Lambda表达式的方法体只有一行,大括号,分号,return可以省略不写,需要同时省略
 */
        //利用Lambda表达式调用方法
        Integer [] arr = {1,2,3,4,5,6,7,8,9,10};

        //使用匿名内部类的方法
        Arrays.sort(arr,new Comparator<Integer>(){
            @Override
            public int compare(Integer o1,Integer o2){
                return o1 - o2;
            }
        });


        //2.利用Lambda表达式的完整格式
        Arrays.sort(arr,(Integer o1,Integer o2)->{
                return o2-o1;
            }
        );

        //Lambda表达式的省略格式
        Arrays.sort(arr,(o1 , o2) -> o1-o2 );

        System.out.println(Arrays.toString(arr));
    }
}
(5)Lambda表达式练习

需求:

定义一个数组并存储以西而字符串,利用Arrays中的sort方法进行排序

按照字符串的长度进行排序,短视的在前面,长的在后面(暂时不比较字符串里面的内容)

package com_05_DataStructure._06lambda;

import java.util.Arrays;
import java.util.Comparator;

public class LambdaTest03 {
    public static void main(String[] args) {
/*
需求:
定义一个数组并存储以西而字符串,利用Arrays中的sort方法进行排序
按照字符串的长度进行排序,短视的在前面,长的在后面(暂时不比较字符串里面的内容)
 */

        String [] arr = {"a","aaaa","aaa","aa"};
        //如果我们以后要把数组中的数据按照指定的方式进行排列,就需要用到sort方法,而且要制定排序的规则

        //使用匿名内部类的的方法
        Arrays.sort(arr, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                //排序的规则
                return o1.length() - o2.length();
            }
        });

        //2.使用Lambda表达式的完整格式
        Arrays.sort(arr,(String o1, String o2)-> {
                //排序的规则
                return o1.length() - o2.length();
            }
        );

        //3.使用Lambda的省略格式
        Arrays.sort(arr,( o1, o2)-> o1.length() - o2.length());

        System.out.println(Arrays.toString(arr));
    }
}

4.综合练习

(1)练习一

需求:定义数组并存储一些女朋友的对象,利用Arrays中的sort方法进行排序

要求1:属性有姓名,年龄,身高

要求2:按照年龄的大小进行排序,年龄一样,按照身高排序,身高一样按照姓名的字母进行排序

(姓名中不要有中文或特殊字符,会涉及到后面的知识)

package com_05_DataStructure._06Test;

public class girlFriend  {
    private String name;
    private int age;
    private double height;

    public girlFriend() {
    }

    public girlFriend(String name, int age, double height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

}
package com_05_DataStructure._06Test;

import java.util.Arrays;
import java.util.Comparator;

public class Test01 {
    public static void main(String[] args) {
/*
 需求:定义数组并存储一些女朋友的对象,利用Arrays中的sort方法进行排序
要求1:属性有姓名,年龄,身高
要求2:按照年龄的大小进行排序,年龄一样,按照身高排序,身高一样按照姓名的字母进行排序
(姓名中不要有中文或特殊字符,会涉及到后面的知识)*/

        //1.创建对象
        girlFriend g1 = new girlFriend("xiaoshishi", 22, 1.68);
        girlFriend g2 = new girlFriend("xiaohuihui", 23, 1.65);
        girlFriend g3 = new girlFriend("xiaodandan", 18, 1.63);

        //2.将对象添加到数组中
        girlFriend [] arr = {g1,g2,g3};

        //3.利用匿名内部类中的sort方法进行排序
        Arrays.sort(arr, new Comparator<girlFriend>() {
            @Override
            public int compare(girlFriend o1, girlFriend o2) {
                //按照年龄的大小进行排序,年龄一样,按照身高排序,身高一样按照姓名的字母进行排序
                double temp = o1.getAge() - o2.getAge();
                temp = temp == 0 ? o1.getHeight() - o2.getHeight() : temp;
                temp = temp == 0 ? o1.getName().compareTo(o2.getName()) : temp;

                if (temp == 0){
                    return 0;
                } else if (temp > 0) {
                    return 1;
                }else {
                    return -1;
                }
            }
        });


        //使用Lambda表达式
        Arrays.sort(arr, (o1, o2) -> {
                //按照年龄的大小进行排序,年龄一样,按照身高排序,身高一样按照姓名的字母进行排序
                double temp = o1.getAge() - o2.getAge();
                temp = temp == 0 ? o1.getHeight() - o2.getHeight() : temp;
                temp = temp == 0 ? o1.getName().compareTo(o2.getName()) : temp;

                if (temp == 0){
                    return 0;
                } else if (temp > 0) {
                    return 1;
                }else {
                    return -1;
                }

        });
        //展示数组中的内容
        System.out.println(Arrays.toString(arr));
    }
}

(2)练习二

不死神兔

有一对兔子,从出生后第三个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问:第十二个月的兔子有多少对?

package com_05_DataStructure._06Test;

public class Test02 {
    public static void main(String[] args) {
/*
不死神兔
有一对兔子,从出生后第三个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问:第十二个月的兔子有多少对?
1月:1    二月:1    三月:2    四月:3    五月:5    六月:8
 */

        //特点:从第三个数字开始,后面的数据是前两个数据之和
        //解法1:
        //1.定义一个数组用来存储月份
        int [] arr = new int[12];
        //2.将第一月和第二月的数量添加到数组
        arr[0] = 1;
        arr[1] = 1;
        //3.利用循环给剩余的数据进行赋值
        for (int i = 2; i < arr.length; i++) {
            arr[i] = arr[i-1] + arr[i-2];
        }
        System.out.println(arr[arr.length-1]);


        //解法2:递归思想
        System.out.println(getSum(12));

    }
    public static int getSum(int month){
        if(month == 1 || month == 2){
            return 1;
        }else{
            return getSum(month-1) + getSum(month-2);
        }
    }
}

(3)练习3:猴子吃桃子

一堆桃子,猴子第一天吃了其中的一半,并多吃了一个,以后每天都吃当前剩下的一半,然后再多吃一个,第十天的时候还没吃,发现只剩下一个桃子了,问:最初总共有多少个桃子?

package com_05_DataStructure._06Test;

public class Test03 {
    public static void main(String[] args) {
/*
一堆桃子,猴子第一天吃了其中的一半,并多吃了一个,以后每天都吃当前剩下的一半,然后再多吃一个,
第十天的时候还没吃,发现只剩下一个桃子了,问:最初总共有多少个桃子?
 */

        System.out.println(getSum(1));
    }
    public static int getSum(int day){
        if (day < 0 || day >= 11){
            System.out.println("当前时间错误");
        }
        if (day == 10){
            return 1;
        }else{
            return (getSum(day+1)+1)*2;
        }
    }
}

(4)爬楼梯

小明有时候一次爬一个台阶,有时候一次爬两个台阶,如果这个楼梯有20个台阶,小明一共有多少种爬法?

package com_05_DataStructure._06Test;

public class Test04 {
    public static void main(String[] args) {
//小明有时候一次爬一个台阶,有时候一次爬两个台阶,如果这个楼梯有20个台阶,小明一共有多少种爬法?

        System.out.println(getCount(20));

    }
    public  static int getCount(int n){
        if (n == 1){
            return 1;
        }
        if (n == 2){
            return 2;
        }
        return getCount(n-1)+getCount(n-2);
    }
}

(5)爬楼梯扩展

小明有时候一次爬一个台阶,有时候一次爬两个台阶,有时候一次爬三个台阶,如果这个楼梯有100个台阶,小明一共有多少种爬法?

package com_05_DataStructure._06Test;

public class Test05 {
    public static void main(String[] args) {
//小明有时候一次爬一个台阶,有时候一次爬两个台阶,有时候一次爬三个台阶,如果这个楼梯有100个台阶,小明一共有多少种爬法?

        System.out.println(getCount(100));
    }
    public static int getCount(int n){
        if (n == 1){
            return 1;
        }
        if (n == 2){
            return 2;
        }
        if (n == 3){
            return 4;
        }
        return getCount(n-1)+getCount(n-2)+getCount(n-3);
    }
}

你可能感兴趣的:(学习笔记,java,算法,学习)