JAVA学习日记2021.11.02——递归与快速排序

一.递归算法

1.什么是递归算法

递归就是自己调用自己,直到满足某个条件结束自己调用自己的过程。

2.递归3个条件

①递归边界条件、②递归前进段、③递归返回段

做递归算法时 一定要有一个明确的结束条件,否则会发生死循环和栈内存溢出

package cn.kgc.kb1620211102;

/**
 * @Author $(USER)
 * @Date $(DATE)
 * @Description 递归输出0-100
 */
public class digui {
    private  static int i=0;
    static void test(){
        i++;
       //递归
        if(i<=100){   //边界条件
            System.out.println(i);
            test();
        }else{
            System.out.println("游戏结束");
        }

    }

    public static void main(String[] args) {
        test();

    }
}

二.快速排序

·拿出数组中第一个位置的值记为k。
例如:arr[] arr = {5,2,4,9,7}; k=arr[0];此时的arr[0]=5
第一步操作:将数组将k右侧所有数据以从后往前的顺序与k值进行对比大小,找到比k值小的数据将两值互换位置。
例如:此时k=5
将k右侧的值从后往前的顺序与k比大小,因为4比5小,将原来arr[2]与arr[0]经行替换, arr = {4,2,5,9,7}。
第二部操作:进行过一次从后往前比大小的替换操作后,不继续替换。换为k值左侧数据从前往后比大小,找到比k值大的数据将两值互换位置。
例如:此时依然是k=5 arr = {4,2,5,9,7}
将k左侧的值从前往后的顺序与k比大小,4和5比过大小没必要继续对比,又因为2比5小,所以不进行替换,以上两部操作,右侧从后往前找比k值小的值并互换位置 到 左侧从前往后找比k值大的值并互换位置 记为一个循环。

·重复以上的循环操作
再将该数组中第一位作为k,对比到原k值得前一位结束。也就是k=4,对比到值为2的位置结束。
第一步操作:将数组将k右侧所有数据以从后往前的顺序与k值进行对比大小,找到比k值小的数据将两值互换位置。
例如:此时k=4 arr = {4,2 ,5 ,9,7}
2比4小,所以讲两值位置互换如arr = {2,4,5 ,9,7},替换过后再进行k左侧数据从左往右的查找。
第二部操作:进行k左侧数据从前往后比大小,找到比k大的值将两值位置互换。
例如:此时依然是k=4 但arr = {2,4,5 ,9,7}
从左侧的数据中进行从前往后的比大小,找到比k值大的数据将两值互换位置。此时4的左侧
没有符合条件的数据,又一次循环结束
执行到此,因为以上操作为递归完成,且原k值5的左侧已经完全排序完成,左边序列递归结束,弹栈进行下一步右边序列递归,也就是将右侧的数据进行排序(提供的代码中有注解)。
·弹栈后的k值是原k值5,此次将从5的后一位作为新的k值也就是9开始排序到数组最后一位。
例如:此时k=9 arr = {4,2 ,5 ,9,7}
经过以上循环9和7会互换位置,最终完成数组的排序, arr = {4,2 ,5 ,7,9 }
通过以上例子不难发现,第一次循环时对比的范围是整个数组,第一次循环后,对比的范围是k值左侧的数据,并把左侧数据的第一位作为新的k值,再次经行排序。此时原k值左侧的所有数据与新的k值进行排序。同理递归弹栈后完成原k值右侧所有数据的排序。
如果数组中数据量比较大,在循环一次后,开始对k值左侧的数据进行排序,又一次循环后又将原k值左侧的数据以新的k值分隔成左右两侧进行上述循环,直至原k值左侧所有数据排序完成,同理再进行原k值右侧数据的排序。
 

 

 /**
     * 快排,用递归,每次保证大于基准值的在右边,小于基准值的在左边
     *
     * @param a 待排序数组
     * @param s 数组起始位置
     * @param e 数组结束位置
     */
    public static void sort(int[] a, int s, int e) {
        if (s >= e) {//递归退出条件,当数组中只有一个元素或没有元素
            return;
        }
        int i = s;//因为在循环中,下标会不停的动,因此需要一个临时变量
        int j = e;//而不是动数组的开始和结束
        int num = a[s];//每次以数组的第一个元素来作为基准值
        while (i < j) {//只要没有找到基准值的位置,就需要继续判断
            while (num <= a[j] && j > i)//只要满足顺序就继续
                j--;
            a[i] = a[j];//不满足顺序的,就向左放到对应位置
            while (num >= a[i] && i < j)//只要满足顺序就继续
                i++;
            a[j] = a[i];//不满足顺序的,就向右放到对应位置
        }
//                a[i] = num;
            a[i] = num;//i和j相等就是基准值的位置
            sort(a, s, i - 1);//基准值左边的数组作为 新数组,继续上面的过程
            sort(a, i + 1, e);//基准值右边的数组作为 新数组,继续上面的过程
        }


        public static int[] randomArray ( int length){
            int[] a = new int[length];
            for (int i = 0; i < a.length; i++) {
                a[i] = (int) (Math.random() * length * 10);
            }
            return a;
        }




    public static void main(String[] args) {
        int[] a = randomArray(10);
        System.out.println(Arrays.toString(a));
        sort(a, 0, a.length - 1);
        System.out.println(Arrays.toString(a));
    }
}

Guess you like

Origin blog.csdn.net/kkkyzp/article/details/121103343