[Java学习日记]查找、排序、递归、lambda表达式

目录

一.分块查找

二.冒泡排序

三.选择排序

四.插入排序

五.快速排序

六.数组帮助类Arrays

七.Arrays.sort方法反向排序

八.Lambda表达式

九.Lambda表达式省略规则与函数式接口细节

十.案例:多条件排序GF

十一.递归案例:爬台阶

十二.递归案例:爬台阶进阶


一.分块查找

分块查找(简便版)
现有数据:分块,如1-100,100-200,200-300,块与块之间按顺序排列
但是,块中的数据无序,这种情况可以分块查找
分块数量接近为:sqrt(总数量),target在哪一块,就在哪一块挨个查找

1.分块查找数组的流程?
1.定义块类,属性值为开始下标,结束下标,最大值
2.创建根据数组(已知情况)创建块对象,放到数组中
3.创建findBlock方法(块数组,target),查找块的下标,找不到返回-1
4.创建findIndex(arr,块数组,target)根据块的下标,得到在arr数组中的查找的范围
在这个范围中查找arr,找不到返回-1

2.分块查找拓展:数据分块,但是块与块之间无序,应该怎么办?
在block类里面多加一个min代表最小值即可
public class Demo211 {
    public static void main(String[] args) {
        int[] arr = {1, 2, 5, 2, 15, 19, 12, 13, 25, 29, 28, 21, 35, 36, 38, 34};
        //创建块的对象
        Block block1 = new Block(5,0,4);
        Block block2 = new Block(19,5,8);
        Block block3 = new Block(29,9,12);
        Block block4 = new Block(38,13,16);
        //定义数组管理块
        Block[] blocks = {block1,block2,block3,block4};
        //定义变量记录查找元素,先查找块再查找下标
        int num = 38;
        System.out.println(getIndex(num,blocks,arr));
    }
    // 查找块
    private static int getBlockIndex(int num, Block[] blocks) {
        for (int i = 0; i < blocks.length; i++) {
            if (num<=blocks[i].getMax())
                return i;
        }
        return -1;
    }
    //查找下标
    private static int getIndex(int num, Block[] blocks, int[] arr) {
        int index = getBlockIndex(num, blocks);
        if (index==-1) return -1;
        Block block = blocks[index];
        int start = block.getStartIndex();
        int end = block.getEndIndex();
        for (int i = start ; i <=end; i++) {
            if(arr[i]==num)
                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;
    }
}


二.冒泡排序

每过一遍数组,比较相邻两个数确定一个数放到最后面即可,大的往后靠
public class Demo212 {
    public static void main(String[] args) {
        int[] arr = new int[]{1, 2, 5, 4, 0, 3, 6, 9, 8, 7};
        bubbleSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    private static void bubbleSort(int[] arr) {
        System.out.println("第一层循环:循环数组长度次数-1即可:10个数据,循环9次能确定9个数的位置,最后一个就不用循环了");
        System.out.println("第二层循环:每次循环减少一个排序目标,故减去i,循环内部i与i+1比较,再减一保证数组不越界");
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }
}


三.选择排序

从0索引开始与后面的元素比较,小的放前面,大的放后面,确定数字的顺序是从前往后确定的
public class Demo213 {
    public static void main(String[] args) {
        int[] arr = new int[]{1, 2, 5, 4, 0, 3, 6, 9, 8, 7};
        selectionSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    private static void selectionSort(int[] arr) {
        System.out.println("第一层循环确定循环次数<length-1次");
        System.out.println("第二层循环i确定比较元素I(守馆人),j确定比较元素J(踢馆选手)");
        System.out.println("j不需要设置成i,初始值设置为i+1,j最大值到数组最后");
        for (int i = 0; i < arr.length - 1; 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;
                }
            }
        }
    }
}


四.插入排序

把前面的数字看作有序,把后面的数字看作无序,把后面的数据一个一个放到前面的有序数组中
public class Demo214 {
    public static void main(String[] args) {
        int[] arr = new int[]{1, 2, 5, 4, 0, 3, 6, 9, 8, 7};
        insertionSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    private static void insertionSort(int[] arr) {
        System.out.println("1.寻找找开始下标,排除数组已经全部排好的情况");
        int startIndex  = 0;
        for (int i = 0; i < arr.length-1; i++) {
            if (arr[i]>arr[i+1]){
                startIndex = i+1;
                break;
            }
        }
        if (startIndex == 0) startIndex=arr.length;

        System.out.println("2.开始在下标:"+startIndex+"搜索,i为要插入的数据,范围是从index到length-1");
        for (int i = startIndex; i < arr.length ; i++) {
            //记录num:记录被选中的数字
            //记录j:记录被选中的数字应该插入的位置,从index开始往前移
            int j = i;
            int num = arr[i];
            //这里的循环意义是:比较前面一个数是否比要插入的数据大,如果大就把前面的数据往后搬
            //否则此处就是正确的位置,停下来插入,j能够记录下num应该插入的地方(当然也可以定义第三个参数交换位置一步一步挪)
            while (j > 0 && arr[j-1]>num) {
                arr[j] = arr[j-1];
                j--;
            }
            //在循环外面插入数据即可
            arr[j] = num;
        }
    }
}


五.快速排序

大致步骤:利用递归思想:大问题拆解成为小的问题:方法调用自己
1.把0索引作为中标,移动之后,中标的左边都是比他小的,右边都是比它大的
2.怎么做呢?设置左右标,右标向左找比中标小的,逮到了一个就停,那么左标就找比右标大的,逮到了就停下
3.然后做什么事情就知道了:交换左右标上面的数字,左右标继续移动找人
4.直到他们相等,相等之后,把第一个基准数与重合的地方的数字交换就可以了(基准数归位)
接下来就按上面的方法分别排序基准数左边的数字与右边的数字
public class Demo215 {
    public static void main(String[] args) {
        int[] arr = new int[50];
        Random random = new Random();
        for (int i = 0; i < arr.length; i++) {
            arr[i] = random.nextInt(100);
        }

        quickSort(arr,0,arr.length-1);
        System.out.println(Arrays.toString(arr));
    }

    //1.创建函数,参数:数组,开始索引,结束索引
    public static void quickSort(int[] arr, int start, int end) {
        //2.结束条件:start>=end就不排
        if (start >= end) return;

        //3.创建左右标与基准数
        int i = start;
        int j = end;
        int mid = arr[i];

        //4.开始循环
        while (i != j) {
            /*
            注意点一:
            必须是先移动j再移动i:先移动i有可能把i撞到比mid大的数上去,而重合的地方又需要和基准数交换,
            而先移动j,停下来就两种情况:碰到i或者碰到比它小的
            第一种情况,重合,肯定能与基准数交换(i从0索引开始)
            第二种情况:等着i拥入怀里到来就可以了

            注意点二:
            这里这一个等于条件:等于就不管它,反正后面的会接着排号的
            如果这里没有写等于:如碰到i,j都碰到两个等于mid的数:就造成死循环
            */

            //5.移动左右标,寻找数字
            while (arr[j] >= mid && i != j) {
                j--;
            }
            while (arr[i] <= mid && i != j) {
                i++;
            }

            //6.交换数字
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }

        //7.把第一个数设置为左右标重合的那个数,把左右标重合那个数设置为基准数
        arr[start] = arr[i];
        arr[i] = mid;

        //注意点三:这里如果设置成i-1,有可能造成i-1<start的问题,在方法开始加一个结束条件即可
        //8.开始递归
        quickSort(arr, start, i - 1);
        quickSort(arr, i + 1, end);
    }
}


六.数组帮助类Arrays

1.如何拷贝数组返回一个新数组?(区别于System.arrayCopy)
2.如果传入数组参数后再传一个参数和两个参数分别代表什么?传入的参数导致数组越界怎么办?
3.如何把数组中所有值设置为一个固定值?
4.如何排序数组?
5.如何指定范围排序数组?
public class Demo216 {
    public static void main(String[] args) {
        int[] arr = {1,2,5,8,7,4,6,9,0,3};
        System.out.println("1.拷贝数组,返回新数组,可以不用自己创建新数组复制了,数组越界补默认值");
        System.out.println(Arrays.toString(Arrays.copyOf(arr,arr.length)));

        System.out.println("2.拷贝指定坐标数组,返回新数组(包头不包尾), 数组越界补默认值");
        System.out.println(Arrays.toString(Arrays.copyOfRange(arr,6,15)));

        System.out.println("3.填充数组方法");
        int[] arr1 = new int[10];
        Arrays.fill(arr1,6);
        System.out.println(Arrays.toString(arr1));

        System.out.println("4.排序数组,默认排序:双轴快速排序,比传统快排更快");
        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));

        System.out.println("5.指定排序方式:指定下标排序");
        int[] arr2 = {1,2,5,8,7,4,6,9,0,3};
        Arrays.sort(arr2,0,5);
        System.out.println(Arrays.toString(arr2));
    }
}


七.Arrays.sort方法反向排序

1.如何使用Arrays帮助类的默认快速排序方法反向排序?
方法:Arrays.sort方法中传入数组与Comparator接口的实现类

2.对于数组中的数据有什么限制?
只能给引用数据排序

3.该方法底层利用插入排序+二分查找进行排序,大致过程如下:
遍历无序的序列里面得到每一个元素:把这个元素A插入序列(用二分查找确定插入点)
把A元素与插入点元素进行比较,比较规则就是compare的方法体
返回为负,A走前半,返回大于等于0,A走后半,直到确定A的位置
如果你从小到大排,可以返回A值-B值

4.这里只需要重写compare函数:
compare形参:o1代表右边遍历的元素A,o2就是左边有序序列中的元素
public class Demo217 {
    public static void main(String[] args) {
        Integer[] arr = {0,2,5,8,9,6,3,1,4,7};
        Arrays.sort(arr, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.print(o1+" "+o2+"  ");
                return o2-o1;
            }
        });
        System.out.println();
        System.out.println(Arrays.toString(arr));
    }
}


八.Lambda表达式

1.lambda表达式最基本的特点?
2.函数式编程(Function Programing)的特点是什么?
3.lambda表达式能简化所有的匿名内部类吗?
4.函数式接口的特征?用什么标注?
5.lambda表达式基本格式?
public class Demo218 {
    public static void main(String[] args) {
        System.out.println("1.lambda表达式最基本的特点:简化匿名内部类的书写(JDK8后出现)");
        System.out.println("2.函数式编程(Function Programing)的特点是忽略面向对象的复杂语法。强调做什么,而不是谁去做");
        System.out.println("3.lambda表达式能简化只能简化函数式接口的匿名内部类,不能简化抽象类。");
        System.out.println("4.函数式接口只有一个抽象方法的接口,使用@FunctionalInterface标注");
        System.out.println("5.lambda表达式基本格式:()->{}");
        Integer[] arr = {0, 1, 2, 3, 4, 5, 6, 7, 8};
        Arrays.sort(arr, (Integer o1, Integer o2) -> { return o1 - o2; });
    }
}


九.Lambda表达式省略规则与函数式接口细节

1.lambda表达式省略核心:能够从原来接口中推导出来的就可以省略
2.默认方法是抽象方法吗?
由于默认方法已经有了实现,所以它们不是抽象方法

3.如果一个接口中声明的抽象方法是重写了Object类中任意一个public方法
那么这些抽象方法并不会算入接口的抽象方法数量中
因为任何接口的实现类都会从其父类Object或其它地方获得这些方法的实现。

4.有多个方法的接口就不是函数式接口了吗?
有多个方法的接口,只要只有一个自己声明的抽象方法,就是函数式接口。
public class Demo219 {
    public static void main(String[] args) {
        method(a->a+666);
    }
    public static void method(Swim swim) {
        System.out.println("1.方法可以省略参数类型,只有一个参数则可省略大括号");
        System.out.println("2.只有一条语句的时候可以不写分号与大括号,可以不写return标识符,也能够return");
        System.out.println(swim.swimming("嘎嘎"));;
    }
}

@FunctionalInterface
interface Swim {
    String swimming(String a);
    boolean equals(Object o);
    default void swimming2(){}
}


十.案例:多条件排序GF

案例:按照年龄排序GF,年龄相同则按照身高排序,身高相同则按照名字排序
1.String中compareTo方法返回的数字代表什么?
2.比较了年龄了,直接返回吗?
public class Demo2110 {
    public static void main(String[] args) {
        System.out.print("1.String中compareTo方法返回的负数为小于,正数为大于:");
        System.out.println("ab".compareTo("abcd"));
        GirlFriend[] girlFriends = {
                new GirlFriend("Alice", 18, 160),
                new GirlFriend("SeaLufee", 18, 160),
                new GirlFriend("Lockxi", 18, 160)
        };
        System.out.println("2.看年龄是否相同接着在lambda表达式里面继续比较");
        Arrays.sort(girlFriends, ((o1, o2) -> {
            double i = o1.getAge() - o2.getAge();
            i = i == 0 ? o1.getHeight() - o2.getHeight() : i;
            i = i == 0 ? o1.getName().compareTo(o2.getName()) : i;
            if (i > 0) {
                return 1;
            } else if (i < 0) {
                return -1;
            } else return 0;
        }));
        for (GirlFriend girlFriend : girlFriends) {
            System.out.println(girlFriend);
        }
    }
}

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;
    }
    @Override
    public String toString() {
        return "GirlFriend{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                '}';
    }
}


十一.递归案例:爬台阶

对于一节台阶,只有一种方法
对于两节台阶,有两种爬法
对于20阶台阶:
如果爬上了19阶,则剩下一种爬法:
如果爬上了18阶,则剩下两种爬法:第一种是爬上19阶(被包含在F(19)了),第二种方法是爬上20
20阶的爬法=19阶爬法+18阶爬法
public class Demo2111 {
    public static void main(String[] args) {
        System.out.println(ways(20));
    }
    public static int ways(int num){
        if (num==1){
            return 1;
        }
        if (num==2){
            return 2;
        }
        return ways(num-1)+ways(num-2);
    }
}


十二.递归案例:爬台阶进阶

//案例:爬台阶一次可以爬1,2,3次
public class Demo2112 {
    public static void main(String[] args) {
        System.out.println(ways(20));   
    }
    public static int ways(int num){
        if (num==1){
            return 1;
        }
        if (num==2){
            return 2;
        }
        if (num==3){
            return 4;
        }
        return ways(num-1)+ways(num-2)+ways(num-3);
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值