大厂面试-算法优化:冒泡排序你会优化吗?

关注公众号:”奇叔码技术“
回复:“java面试题大全”或者“java面试题”
即可领取资料
大厂面试-算法优化:冒泡排序你会优化吗?_第1张图片

原文:冒泡排序及优化代码

https://blog.csdn.net/weixin_43989347/article/details/122025689

原文:十大经典排序算法


https://frxcat.fun/pages/eab19d/

内容分为:

1、总结算法思路

2、冒泡排序算法演示图

3、冒泡排序算法可运行代码

4、大厂面试会问到算法和算法优化

一、总结算法思路

冒泡排序是经典算法了,它的时间复杂度:最好O(n),最坏O(n^2)。

接下来直接说明它的优化算法思路:


自己理解:

第一次优化是指:如果内层循环经过一轮的比较,没有进入if判断语句进行交换,则代表后续的元素已经排好序了,已经是小的在前面,大的在后面,则也就证明了不用下一轮的比较了,直接退出循环,返回结果。


第二次优化是指:在原有第一次优化的基础上进行记录,经过内层循环的一轮比较,进入if判断语句,第j个数和第j+1个数比较,记录进行交换的交换位置的第j个数。内层循环一轮比较完毕之后,记录的第j个数,证明了,该数后面的数都已经排好序了,无序再进行排序。则下一轮的内层循环比较的最大索引位置就是第j个数,依此类推。


原作者的理解:

第一次优化:经过一轮的比较,如果没有交换,说明已经排好序了

第二次优化:记录每次最后一次交换的位置,说明这个位置往后,都是已经排好序了;那么下轮比较时,只需要比较到上次记录索引的位置即可。

二、冒泡排序算法演示图

冒泡排序

三、冒泡排序算法可运行代码

//冒泡排序,最好的O(n),最坏的O(n^2)
//第一次优化是指,如果内层循环经过一轮的比较,没有进入if判断语句进行交换,则代表后续的元素已经排好序了,已经是小的在前面,大的在后面,则也就证明了不用下一轮的比较了,直接退出循环,返回结果。
//第二次优化是指,再原有第一次优化的基础上进行记录,经过内层循环的一轮比较,进入if判断语句,第j个数和第j+1个数比较,,记录进行交换的交换位置的第j个数,
//内层循环一轮比较完毕之后,记录的第j个数,证明了,该数后面的数都已经排好序了,无序再进行排序。则下一轮的内存循环比较的最大索引位置就是第j个数,以此类推。
//原作者的理解:
//第一次优化:经过一轮的比较,如果没有交换,说明已经排好序了
//第二次优化:记录每次最后一次交换的位置,说明这个位置往后,都是已经排好序了;那么下轮比较时,只需要比较到上次记录索引的位置即可。


/*
 * n是数组个数,i代表循环次数,j代表每轮比较次数,count是算法一共比较的次数,
 * 冒泡排序:例子是从小大到排序
 *
 * 规律:
 *   从第一个数,依次往后进行比较,若第一个大于第二个数,则交换。(稳定排序)
 *   每一轮for循环,比较出一个最大或最小的数,放在确定的位置。

 *
 *
 * */
public class BulleSort {
    public static void main(String[] args) {
        bubble1();
        /*
        * bubble1();
        * 循环次数:
        *   n-1次    比如3个数,最多只需要循环2次,就可以得出结果
        * 每轮比较次数:
        *   n-1-i次  第一轮比较n-1,第二轮比较n-2,最后一轮比较n-1-(n-2)=1次
          这个算法,是固定循环n-1次,并且固定每轮比较次数:[n*(n-1)]/2
        * 缺点:
           当出现只需要交换一次的数组:{2,1,3,4,5},再用上面方法就资源浪费了
            排序前:
            2,1,3,4,5,
            排序后:
            1,2,3,4,5,
            总共比较次数:10  //优化后其实只需要比较7次就可以了
        */

       bubble2();
        /*
        * 优化:
        *   减少不必要的循环和比较次数。
        * 目标:
        *   数组{2,1,3,4,5},只需要循环2次,比较前两次循环的次数:(n-1)+(n-2)
        * 结果:
            排序前:
            2,1,3,4,5,
            排序后:
            1,2,3,4,5,
            总共比较次数:7

        */
        bubble3();
        /*
        * 经过上面的优化,可以将固定的比较次数,减少到循环2次,比较前两次循环次数
        * 那么有没有更好的优化方法呢?
           比如只要循环一次,就可以知道下次从没有确定最终位置的地方开始
        * 目标:
        *  1:数组{2,1,3,4,5},只需要循环1次,比较第1次循环的次数:(n-1)
        *  2:数组{1,2,3,5,4},只需要循环2次,比较前两次即可,是因为方法buble2()的test=1/0
        * 方法:
        *   记录每次最后一次交换的位置,说明这个位置往后,都是已经排好序了
        *   那么下轮比较时,只需要比较到上次记录索引的位置即可。
        *
        * */

    }

    public static void bubble3(){
        System.out.println("\n"+"方法三:每次循环,只需要比较未确定最终位置的数");
        int count=0;                        //总共比较次数
        int[] arr = {3,44,38,5,47,15,36,26,27,2,46,4,19,50,48};           //排序的数组
        int n = arr.length;                 //数组中有几个数

        int test = 0;
        /*如果某一次循环,没有交换,那就是已经排好序了。那么就退出。
        1假如可能排好序了,0代表肯定没有排好序 */
        int p1=0;   // 记录最后一次交换位置
        int p2=n-1;
        /*由于j循环,每次都需要判断j的本次i轮循环的最大比较位置
        所以需要引出p2,来通过本次确定已经排好序的位置,
        下次i轮循环时,j需要比较最大索引位置即可
        那么初始化,第一次比较次数应该是n-1次*/

        System.out.print("排序前:");
        print_Array(arr, n);                //打印数组

        //冒泡排序算法:
        for (int i = 0; i < n-1; i++) {        //一共循环n-1次
            test=1;                            //默认排好序了
            for (int j = 0; j < p2; j++) {  //比较n-1-i
                count++;                 //统计比较次数
                if(arr[j]>arr[j+1]) {          //第一个数和第二个数比较
                    test =0;                   //说明目前没有排好序
                    swap(arr,j,j+1);       //若第j个数大于第j+1个数,则交换
                    p1 = j;
                }
            }
            p2=p1;
            //下一轮比较的最大索引位置

            if(test==1) break;
            //经过一轮的比较,如果没有交换,说明已经排好序了
            p_Array(arr,n,i);                    //每轮循环的数组
        }
        System.out.print("排序后:");
        print_Array(arr, n);
        System.out.println("总共比较次数:"+count);
    }

    public static void bubble2(){
        System.out.println("\n"+"方法二:假如一次循环都没有交换,则说明已排好序");
        int test = 0;
        //如果某一次循环,没有交换,那就是已经排好序了。那么就退出。
        //1假如可能排好序了,0代表肯定没有排好序
        int count=0;                        //总共比较次数
        int[] arr = {3,44,38,5,47,15,36,26,27,2,46,4,19,50,48};           //排序的数组
        int n = arr.length;                 //数组中有几个数
        System.out.print("排序前:");
        print_Array(arr, n);                //打印数组

        //冒泡排序算法:
        for (int i = 0; i < n-1; i++) {        //一共循环n-1次
            test=1;                            //默认排好序了
            for (int j = 0; j < n-1-i; j++) {  //比较n-1-i
                count++;                 //统计比较次数
                if(arr[j]>arr[j+1]) {          //第一个数和第二个数比较
                    test =0;                   //说明目前没有排好序
                    swap(arr,j,j+1);       //若第j个数大于第j+1个数,则交换
                }
            }
            p_Array(arr,n,i);                    //每轮循环的数组
            if(test==1) break;
            //经过一轮的比较,如果没有交换,说明已经排好序了
        }

        System.out.print("排序后:");
        print_Array(arr, n);
        System.out.println("总共比较次数:"+count);
    }

    public static void bubble1(){
        System.out.println("方法一:未优化");
        int count=0;         //统计一共比较多少次数
        int[] arr = {3,44,38,5,47,15,36,26,27,2,46,4,19,50,48};           //排序的数组
        int n = arr.length;  //数组中有几个数
        System.out.print("排序前:");
        print_Array(arr, n);          //打印数组

        //冒泡排序算法:
        for (int i = 0; i < n-1; i++) {        //一共循环n-1次
            for (int j = 0; j < n-1-i; j++) {  //比较n-1-i
                count++;                       //统计比较次数
                if(arr[j]>arr[j+1]) {          //第一个数和第二个数比较
                    swap(arr,j,j+1);       //若第j个数大于第j+1个数,则交换
                }
            }
            p_Array(arr,n,i);                    //每轮循环的数组
        }

        System.out.print("排序后:");
        print_Array(arr, n);          //打印数组
        System.out.println("总共比较次数:"+count);
    }


    //打印数组
    private static void print_Array(int[] arr, int length) {
        for (int i = 0; i < length; i++) {
            System.out.print(arr[i] + ",");
        }
        System.out.println();
    }
    //交换数组中两个数的位置
    public static void swap(int[] a,int a0,int a1){
        int temp = a[a0];
        a[a0] = a[a1];
        a[a1] = temp;
    }

    //打印每循环一轮的数组
    public static void p_Array(int[] arr,int length,int i1){
        System.out.print("第"+(i1+1)+"轮循环的数组:");
        for (int i = 0; i < length; i++) {
            System.out.print(arr[i] + ",");
        }
        System.out.println();
    }
}

四、大厂面试会问到算法和算法优化:

冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端。

作为最简单的排序算法之一,冒泡排序给我的感觉就像 Abandon 在单词书里出现的感觉一样,每次都在第一页第一位,所以最熟悉。


1.算法步骤

比较相邻的元素。如果第一个比第二个大,就交换他们两个。

对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。

针对所有的元素重复以上的步骤,除了最后一个。

持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。



2.算法优化

(1)记录进入if判断语句中比较之后的最后一次索引位置作为下一次内层循环的结束下标。

(2)记录没有进入if判断语句的flag标志,表明排序已完毕,无序再比较,退出循环,结束。


五、最后!!!

点赞
评论
关注我

END
下篇来临!

你可能感兴趣的:(面试,算法,java)