10大排序算法之二:冒泡排序【稳定的】,但复杂度高,一般不用冒泡排序的

10大排序算法之二:冒泡排序【稳定的】,但复杂度高,一般不用冒泡排序的

提示:整个算法界,一共有十大排序算法,每一个算法都要熟悉,才算是算法入门

算法界的十大排序算法分别是:
选择排序、冒泡排序、插入排序、堆排序、希尔排序、归并排序、快速排序、桶排序、计数排序,基数排序
选择排序:10大排序算法之一:选择排序【不稳定】,一般不用选择排序的

在这里插入图片描述
如果你想进互联网大厂,至少这上面的其中最重要的8种,是必须熟练掌握的:
去掉希尔排序,希尔排序是一种改进的插入排序算法——所以只需要掌握插入排序
桶排序中最重要的就是计数排序和基数排序,都是桶的思想
在这里插入图片描述
根据算法复杂度低一点的,又稳定的
咱们可以最常用的算法实际上就四种:
插入排序(o(n^2))【当数据量小时,这个方法简单】【稳定】、
堆排序o(nlog(n))【不稳定】、
归并排序o(nlog(n))【稳定】,
快速排序o(nlog(n))(虽然快排不稳定,但是很多不需要稳定情况下,快排非常快)
因此,o(n)的桶排序很少用,除非面试官特别申明,否则都用比较排序。
归并排序是最常用的,复杂度低,而且稳定,达到了一个非常好的折中。


题目

请你手撕冒泡排序的算法代码,要求将arr中的数字升序排序。


一、审题

示例:arr = 5 3 1 8 6 2 4
让其最终变为:arr= 1 2 3 4 5 6 8


二、解题

冒泡排序是稳定的排序,但复杂度高o(n^2),系统中一般不用冒泡排序的

冒泡排序的核心思想:
从i=N-1–0倒回来遍历:
每一次,从j=0–i顺着遍历一下,途中两对比,把大的交换到右边,即冒到右边位置
这样子的话,岂不是每一轮,都让最大值冒到最右边,所谓冒泡就是这样的思想
看例子:
arr = 5 3 1 8 6 2 4
看图就知道:
第1论:从0–6位置轮番冒泡:53交换,然后51交换,然后58不动,86交换,82交换,84交换——什么规律?大的往右冒泡!8固定了
第2论:从0–5位置轮番冒泡:31交换,其余不动,62交换,64交换,68固定了——什么规律?大的往右冒泡!
第3论:从0–4位置轮番冒泡:52交换,54交换,568固定了——什么规律?大的往右冒泡!
第4论:从0–3位置轮番冒泡:32交换,4568固定了——什么规律?大的往右冒泡!
第5论:从0–2位置轮番冒泡:一个都不交换,34568固定了——什么规律?大的往右冒泡!
第6论:从0–1位置轮番冒泡:一个都不交换,234568固定了——什么规律?大的往右冒泡!
第7论:从0–0位置轮番冒泡:一个都不交换,1234568固定了——什么规律?大的往右冒泡!
在这里插入图片描述
这里你会发现,冒泡的思想自然是很容易理解的,但是这个算法太垃圾了了,很多对比之下,咱只是对比,也不做有效的交换操作!!!
极其浪费时间,数据量在极少极少的情况下,还能玩玩,但是计算机系统中绝不会用这个冒泡排序算法的!!

显然每一次外边的循环调度,都会让内部调度N次,故时间复杂度为o(N^2)。——选择排序也会是这复杂度,但是不稳定。
如果左边不比右边大的,位置就绝不会交换的,故排序是稳定的哦!!!这点比选择排序好。

手撕代码还不容易?
为啥要手撕代码?
我曾经在文章多次说过,字节跳动的算法题,你idea都不能用,只能在网页上手写,而且连函数提示都没有!
你必须记住相关的函数包如何import,你还要自己手撕数据怎么输入,你更需要优化算法,熟悉相应的系统数据结构,还要手撕算法,他的界面调试很困难,你手撕算法写不对基本很难调试的!
所以平时,自己一定要养成手撕代码的习惯。战场上才不至于慌得一比!
写代码之前,搞懂算法的核心思想,滤清算法的宏观调度,和内部节奏,才知道优化在哪些地方,也知道如何调试。

**为什么字节的算法考试这么狗?**因为出题人都是全球全国顶尖的ACM大佬们,他们平时参赛就是手撕,输入输出也都是ACM格式,而字节要招聘的人,那都是是真正有实力的聪明人,绝不是你会背一点八股文就行的普通人

OK,手撕一下这个题的算法代码
【虽然我是从idea上直接copy这些代码到博客上来的,但是我私底下是踏踏实实手撕代码的】

public static void bubbleSortReview(int[] arr){
        //从i=N-1倒回来调度,这是每次固定右边已经排序好的数组
        int N = arr.length;
        for (int i = N - 1; i > 0; i--) {//i不能到0位置,因为下面依赖有0+1
            //然后每次从0--i来冒泡
            for (int j = 0; j < i; j++) {//不能等于i哦,因为依赖的是j+1
                if (arr[j] > arr[j + 1]) swap(arr, j, j + 1);
            }
        }
    }

    //常用的交换数组函数
    public static void swap(int[] arr, int i, int j){
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

选择排序那文章我们讲过对数器,将咱们手撕的算法,跟系统排序的算法对比,有差错就报错,否则就是right

//对数器之构建随机数组
    public static int[] createArray(int arrSize, int maxValue){
        int[] arr = new int[arrSize];
        for (int i = 0; i < arrSize; i++) {
            arr[i] = (int)(maxValue * Math.random());//0-N-1的随机数
        }
        return arr;
    }

    public static void checker(){
        //生成检验数组
        int[] arr = createArray(500,5);
        int[] arr2 = new int[arr.length];//赋值同样一个数组arr
        for (int i = 0; i < arr.length; i++) {
            arr2[i] = arr[i];//copy即可
        }
        int[] arr3 = new int[arr.length];//赋值同样一个数组arr
        for (int i = 0; i < arr.length; i++) {
            arr3[i] = arr[i];//copy即可
        }

        //绝对的正确方法——暴力方法,或系统函数,操作arr
        Arrays.sort(arr);
        //优化方法,操作arr2
        bubbleSort(arr2);
        bubbleSortReview(arr3);

        //然后两个数组对位校验
        boolean isSame = true;
        for (int i = 0; i < arr.length; i++) {
            if(arr[i] != arr2[i]) {
                isSame = false;
                break;//只要有一个不等,不必继续判断了
            }
        }
        System.out.println(isSame == false ? "oops,wrong!" : "right!");
        isSame = true;
        for (int i = 0; i < arr.length; i++) {
            if(arr[i] != arr3[i]) {
                isSame = false;
                break;//只要有一个不等,不必继续判断了
            }
        }
        System.out.println(isSame == false ? "oops,wrong!" : "right!");
    }

对数器的好处是,差错的话,只需要将arrSize改得很小很小,我们就可以单步运行差错了。
——用idea来debug的好处就是很容易找出自己的逻辑错误在哪,或者条件边界的问题【很多互联网大厂都用idea写代码,然后复制提交,这比字节要美多了!!】
测试代码:

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

结果美滋滋

right!
right!

总结

提示:重要经验:

1)冒泡排序是稳定的排序,但复杂度高o(n^2),系统中一般不用冒泡排序的
2)手撕代码是进入互联网大厂的必备技能,不会,根本过不了大厂的笔试,就是进面试了,手撕不会也会被刷,当然你可能背了很多八股文,但是不会手撕代码工资就被大大压低了。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰露可乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值