常见算法 (笔记)

  1. 基本,二分,插值,斐波那契

基本查找

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

        int[] arr = {131, 127, 147, 81, 103, 23, 7, 79};
        int number = 82;
        System.out.println(basicSearch(arr, number));

    }

    public static boolean basicSearch(int[] arr, int number){
        for (int i = 0; i < arr.length; i++) {
            if(arr[i] == number){
                return true;
            }
        }
        return false;
    }
}
练习题1
    //课堂练习1:
    //需求:定义一个方法利用基本查找,查询某个元素在数组中的索引
    //要求:不需要考虑数组中元素是否重复
public class A01_BasicSearchDemo2 {
    public static void main(String[] args) {
        int[] arr = {131, 127, 147, 81, 103, 23, 7, 79};
        int number = 82;
        basicSearch(arr, number);
    }


    public static int basicSearch(int[] arr, int number) {

        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == number) {
                System.out.println("找到了数字" + number);
                return i;
            }
        }
        System.out.println("没有找到数字" + number);
        return -1;
    }
}
练习题2
    //课堂练习2:
    //需求:定义一个方法利用基本查找,查询某个元素在数组中的索引
    //要求:需要考虑数组中元素有重复的可能性
    //{131, 127, 147, 81, 103, 23, 7, 79, 81}
    //我要查找81,想要返回的是所有索引 3 8
public class A01_BasicSearchDemo2 {
    public static void main(String[] args) {

        int[] arr = {131, 127, 147, 81, 103, 23, 7, 79, 81};
        int number = 81;
        basicSearch2(arr, number);

    }

    public static void basicSearch2(int[] arr, int number) {
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == number) {
                list.add(i);
            }
        }
        System.out.print("我要查找" + number + ",想要返回的是所有索引");
        if (list.isEmpty()) {
            System.out.println("没有找到数字" + number);
        } else {
            for (int j : list) {
                System.out.print(" " + j);
            }
        }
    }

}

二分查找/折半查找

        //二分查找/折半查找
        //核心:
        //每次排除一半的查找范围
        //需求:定义一个方法利用二分查找,查询某个元素在数组中的索引
        //数据如下:{7, 23, 79, 81, 103, 127, 131, 147}
public class A02_BinarySearchDemo1 {
    public static void main(String[] args) {
        int[] arr = {7, 23, 79, 81, 103, 127, 131, 147};
        int number = 7;
        System.out.println(binarySearch(arr, number));
    }

    public static int binarySearch(int[] arr, int number){
        //定义两个变量记住要查找到的范围
        int min = 0;
        int max = arr.length - 1;
        //利用循环去查找要找的数据
        while (true) {
            if (min > max) {
                return -1;
            }
            //找到min和max的中间位置
            int mid = (min + max) / 2;
            //拿着mid指向的元素跟要找的元素进行比较
            //要找的元素在左面,要找的元素在右面,number和指向的元素一样
            if (arr[mid] > number) {
                max = mid - 1;
            } else if (arr[mid] < number) {
                max = mid + 1;
            } else {
                return mid;
            }
        }
    }
}

插值查找

数组数据要均匀否则降低效率

斐波那契查找

  1. 分块.分块扩展,哈希查找

分块查找

查找方法

        /*
            分块查找
            核心思想:
                块内无序,块间有序
            实现步骤:
                1.创建数组blockArr存放每一个块对象的信息
                2.先查找blockArr确定要查找的数据属于哪一块
                3.再单独遍历这一块数据即可
        */
 public static void main(String[] args) {
        int[] arr = {16, 5, 9, 12, 21, 18,
                32, 23, 37, 26, 45, 34,
                50, 48, 61, 52, 73, 66};
        //创建三个块对象
        Block b1 = new Block(21, 0, 5);
        Block b2 = new Block(45, 6, 11);
        Block b3 = new Block(73, 12, 17);
        //定义数组用来管理三个块的对象
        Block[] blockArr = {b1, b2, b3};
        //定义一个变量用来记录要查找的元素
        int number = 37;
        //调用方法,传递索引表,数组,要查找的元素
        int index = getIndex(blockArr, arr, number);
        //打印一下
        System.out.println(index);
    }
 //定义一个方法,用来确定number在哪一块当中
    public static int findIndexBlock(Block[] blockArr, int number) { //100
        for (int i = 0; i < blockArr.length; i++) {
            if (number <= blockArr[i].getMax()) {
                return i;
            }
        }
        return -1;
    }
//利用分块查找的原理,查询number的索引
    //确定number在索引表中的位置
    private static int getIndex(Block[] blockArr, int[] arr, int number) {
        int indexBlock = findIndexBlock(blockArr, number);
        if (indexBlock == -1) {
            return -1;
        }
        int startIndex = blockArr[indexBlock].getStartIndex();
        int endIndex = blockArr[indexBlock].getEndIndex();
        for (int i = startIndex; i <= endIndex; i++) {
            if (arr[i] == number) {
                return i;
            }
        }
        return -1;
    }

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

 public static void main(String[] args) {
        int[] arr = {27,22,30,40,36,13,19,16,20,7,10,43,50,48};
        //创建三个块对象
        Block b1 = new Block(40, 0, 4,22);
        Block b2 = new Block(20, 5, 8,16);
        Block b3 = new Block(10, 9, 10,7);
        Block b4 = new Block(50, 11, 13,43);
        //定义数组用来管理三个块的对象
        Block[] blockArr = {b1, b2, b3, b4};
        //定义一个变量用来记录要查找的元素
        int number = 16;
        //调用方法,传递索引表,数组,要查找的元素
        int index = getIndex(blockArr, arr, number);
        //打印一下
        System.out.println(index);
    }
 public static int findIndexBlock(Block[] blockArr, int number) { //100
        for (int i = 0; i < blockArr.length; i++) {
            if (number <= blockArr[i].getMax() && number >= blockArr[i].getMin()){
                return i;
            }
        }
        return -1;
    }

扩展的分块查找(查找的过程中还需要添加数据)

3.冒泡排序和选择排序

常见算法(排序算法)

冒泡排序

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

        //1.定义数组
        int[] arr = {2, 4, 5, 3, 1};

        //2.利用冒泡排序将数组中的数据变成 1 2 3 4 5

        //外循环:表示我要执行多少轮。 如果有n个数据,那么执行n - 1 轮
        for (int i = 0; i < arr.length - 1; i++) {
            //内循环:每一轮中我如何比较数据并找到当前的最大值
            //-1:为了防止索引越界
            //-i:提高效率,每一轮执行的次数应该比上一轮少一次。
            for (int j = 0; j < arr.length - 1 - i; j++) {
                //i 依次表示数组中的每一个索引:0 1 2 3 4
                if(arr[j] > arr[j + 1]){
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
        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,从0索引开始,跟后面的元素一一比较。
                2,小的放前面,大的放后面。
                3,第一次循环结束后,最小的数据已经确定。
                4,第二次循环从1索引开始以此类推。

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

         */


        //1.定义数组
        int[] arr = {2, 4, 5, 3, 1};


        //2.利用选择排序让数组变成 1 2 3 4 5
       /* //第一轮:
        //从0索引开始,跟后面的元素一一比较。
        for (int i = 0 + 1; i < arr.length; i++) {
            //拿着0索引跟后面的数据进行比较
            if(arr[0] > arr[i]){
                int temp = arr[0];
                arr[0] = arr[i];
                arr[i] = temp;
            }
        }*/

        //最终代码:
        //外循环:几轮
        //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;
                }
            }
        }
        printArr(arr)
    }
}

4.插入排序和递归算法

插入排序

        /*
            插入排序:
                将0索引的元素到N索引的元素看做是有序的,把N+1索引的元素到最后一个当成是无序的。
                遍历无序的数据,将遍历到的元素插入有序序列中适当的位置,如遇到相同数据,插在后面。
                N的范围:0~最大索引

        */
 public static void main(String[] args) {

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

        //1.找到无序的哪一组数组是从哪个索引开始的。  2
        int startIndex = -1;
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] > arr[i + 1]) {
                startIndex = 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;
            }
        }
        printArr(arr);
    }
}

递归算法

 //需求:利用递归求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.找规律
  public static int getSum(int number){//99
        if(number == 1){
            return 1;
        }

        //如果numbert不是1呢?
        return number + getSum(number -1);

    }

递归求阶乘

        //需求:利用递归求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;
  public static int getFactorialRecursion(int number){//5 !
        if(number == 1){
            return 1;
        }

        return number * getFactorialRecursion(number - 1);
    }

5.快速排序

      /*
        快速排序:
            第一轮:以0索引的数字为基准数,确定基准数在数组中正确的位置。
            比基准数小的全部在左边,比基准数大的全部在右边。
            后面以此类推。
      */
 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,从后往前开始找,找比基准数小的数字
            //int[] arr = {1, 6, 2, 7, 9, 3, 4, 5, 10, 8};
            while(true){
                if(end <= start || arr[end] < baseNumber){
                    break;
                }
                end--;
            }
            System.out.println(end);
            //利用start,从前往后找,找比基准数大的数字
            while(true){
                if(end <= start || arr[start] > baseNumber){
                    break;
                }
                start++;
            }



            //把end和start指向的元素进行交换
            int temp = arr[start];
            arr[start] = arr[end];
            arr[end] = temp;
        }

        //当start和end指向了同一个元素的时候,那么上面的循环就会结束
        //表示已经找到了基准数在数组中应存入的位置
        //基准数归位
        //就是拿着这个范围中的第一个数字,跟start指向的元素进行交换
        int temp = arr[i];
        arr[i] = arr[start];
        arr[start] = temp;

        //确定6左边的范围,重复刚刚所做的事情
        quickSort(arr,i,start - 1);
        //确定6右边的范围,重复刚刚所做的事情
        quickSort(arr,start + 1,j);

    }

6.Arrays

Arrays.sort重写降序排列代码

7.Lambda表达式

lambda表达式对匿名内部类进行简化

函数式编程

Lambda表达式格式

什么是函数式接口?

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

        //1.匿名内部类的形式调用method方法
        //调用一个方法的时候,如果方法的形参是一个接口,那么我们要传递这个接口的实现类对象
        //如果实现类对象只要用到一次,就可以用匿名内部类的形式进行书写
        method(new Swim() {
            @Override
            public void swimming() {
                System.out.println("正在游泳~~~");
            }
        });

        //2.利用lambda表达式进行改写
        /*method(() ->{
            System.out.println("正在游泳~~~");
        });*/

    }


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

interface Swim {
    public abstract void swimming();
}

Lambda表达式的省略写法

    /*lambda的省略规则
       1.参数类型可以省略不写
       2.如果只有一个参数,参数类型可以省略,同时()也可以省略
       3.如果lambda表达式的方法体只有一行,大括号,分号,return可以省略不写,需要同时省略
     */
//        lambda的省略格式
//        Arrays.sort(arr, (o1, o2) -> {
//            return o1 - o2;
//        });

//        Arrays.sort(arr, (o1, o2) -> o1 - o2;);
    public static void main(String[] args) {
        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();
            }
        });


        //Lambda完整格式
        Arrays.sort(arr, (String o1, String o2) -> {
                    //字符串的长度进行排序
                    return o1.length() - o2.length();
                }
        );*/
        //Lambda简写格式
        //小括号:数据类型可以省略,如果参数只有一个,小括号还可以省略
        //大括号:如果方法体只有一行 return ,分号,大括号,都可以省略
        Arrays.sort(arr, (o1, o2) -> o1.length() - o2.length());


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

    }

8.五道经典算法题

public class Test1 {
    public static void main(String[] args) {
//        String s1 = "a";
//        String s2 = "b";
//        int i = s1.compareTo(s2);
//        System.out.println(i);//-1 代表s1小于s2 ASCII码比较

        GirlFriend gf1 = new GirlFriend("xiaoshishi", 18, 1.67);
        GirlFriend gf2 = new GirlFriend("xiaodandan", 19, 1.72);
        GirlFriend gf3 = new GirlFriend("xiaohuihui", 19, 1.78);
        GirlFriend gf4 = new GirlFriend("abc", 19, 1.78);
        //定义数组存储女朋友的信息
        GirlFriend[] arr = {gf1, gf2, gf3, gf4};
        //利用Arrays中的sort方法进行排序
        // 匿名内部类 Lambda表达式
        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 1;
                } else if (temp < 0) {
                    return -1;
                } else {
                    return 0;
                }
            }

        });

        //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 1;
            } else if (temp < 0) {
                return -1;
            } else {
                return 0;
            }
        });
        //展示数组中的内容
        System.out.println(Arrays.toString(arr));

    }

}

public class Test2 {
    public static void main(String[] args) {
        /*
        * 特点:第三个数据开始,是前两个数据和(斐波那切数列)
        * */

/*        //求解1:
        //1.创建一个长度为12的数组
        int[] arr = new int[12];

        //2.手动给0索引和1索引的数据进行赋值
        arr[0] = 1;
        arr[1] = 1;
        //3.利用循环给剩余的数据进行赋值
        for (int i = 2; i < arr.length; i++) {
            arr[i] = arr[i - 1] + arr[i - 2];
        }

        //4.获取最大索引上的数据即可

        System.out.println(arr[11]);*/

        //求解2:
        //递归的方式去求解
        //1.递归的出口
        //2.找到递归的规律
        //Fn(12)=Fn(11)+Fn(10)
        //Fn(11)=Fn(10)+Fn(9)
        //Fn(10)=Fn(9)+Fn(8)
        //Fn(9)=Fn(8)+Fn(7)
        //Fn(8)=Fn(7)+Fn(6)
        //...
        //Fn(3)=Fn(2)+Fn(1)
        //Fn(2)=1
        //Fn(1)=1;
        System.out.println(getSum(12));

    }

    public static int getSum(int month) {

        if (month == 1 || month == 2) {
            return 1;
        }
        return getSum(month - 1) + getSum(month - 2);
    }

}
public class Test3 {

    public static void main(String[] args) {
    /*
    day 10: 1
    day 9: (day 10 + 1) * 2 = 4
    day 8: (day 9 + 1) * 2 = 10
    每一天的桃子数量都是后一天数量加1,乘以2

    day 7: 一定会依赖后一天桃子的数量




     */
    }

    public static int getCount(int day) {

        if (day <= 0 || day >= 11) {
            System.out.println("日期错误");
            return -1;
        }
        if (day == 10) {
            return 1;
        }
        //书写规律
        //每一天的桃子树梁都是后一天数量加1,乘2
        return (getCount(day + 1) + 1) * 2;
    }

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

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

    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);
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值