[排序算法总结一] O(n^2)级别的排序算法(冒泡排序、选择排序、插入排序)

0、前言

排序算法我觉得是属于很基础但是又很重要的一部分,在今后的实际工作中肯定会经常遇到,而且排序算法能增加对数据排序的深入理解,自己实现过程中也提高自己动手能力,排序顾名思义就是给串数据给你,需要升序或者降序输出。但是今后工作中的数据会是百万千万级别的,这时候选择合适高效的排序算法是至关重要的。今天先从最基本也是经典的几种排序算法讲起。分别是:

冒泡排序

选择排序

插入排序

1、冒泡排序

冒泡排序:冒泡排序是最早接触,也是印象最深的一种排序方法。对于给定的一串数据,从数据最后面开始遍历,只要小于前面的数,就和前面数交换位置,这样遍历一遍数组后,会把数组中最小的一个数据移动到数组最上面,然后再从最后一个数据开始遍历,再次比较和前面数据大小关系。这样每次遍历数据都会把此次遍历过程中的最小数移动到最前面。示意图如下所示:
在这里插入图片描述
每次遍历过程中,都会把最小数上浮到最上面,貌似气泡上浮,故名冒泡排序。对于n个数据,需要遍历(n - 1)次数组,每次都会移动一个数到数组前面,所以平均下来时间复杂度是O(n^2)。代码实现如下所示:

private void bubbleSort(int[] array , int n) {
        int len = array.length;
        boolean flag = true;
        for (int i = 1 ; i <= len && flag ; i ++) {
            flag = false;
            for (int j = len - 1 ; j >= i; j --) {
                if (array[j] < array[j - 1]) {
                    int temp = array[j];
                    array[j] = array[j - 1];
                    array[j - 1] = temp;
                    flag = true;
                }
            }
        }
    }

这里有个优化地方,使用一个标志flag判断余下数组是否已经排好序了,当余下数据已经是升序的时候,直接break跳出循环。排序的稳定性是指对于相等的两个数,排序后的相对前后位置是否会发生变化,相对前后位置没有发生变化即为稳定的。
冒泡排序时间复杂度是O(n^2),排序是稳定的。

2、选择排序

选择排序:遍历一遍数组,从中选择最小的数据,和第一个数据交换位置,然后再遍历余下数组选择最小的数据,再和第二个数交换位置,每次遍历都会选择当前最小的数,然后和前面交换位置,即每次遍历都会选择一个最小的数。时间复杂度也为O(n^2)。示意图如下所示:
在这里插入图片描述
每次遍历记录最小值的索引即可,然后与未排序的数组第一个元素交换位置。实现代码如下所示:
下面展示一些 内联代码片

private void selectSort(int[] array , int n) {
        int len = array.length;
        for (int i = 0 ; i < len ; i ++) {
            //寻找后面最小的一个数的索引
            int minIndex = i ;
            for (int j = i ; j < len ; j ++) {
                if (array[j] < array[minIndex])
                    minIndex = j;
            }
            int temp = array[i];
            array[i] = array[minIndex];
            array[minIndex] = temp;
        }
    }

时间复杂度是O(n^2),排序是稳定的。

3、插入排序

插入排序:插入排序即把当前数据插入到前面已经排好的数组中,插入即可。

在这里插入图片描述
将3和前面元素比较,只要比前面数据大的就交换位置,因为3肯定就在它的前面,但这样会频繁移动位置,所以可以先把3保存下来,只要前面数比3大,就移位到3位置上来,然后继续和前面数据比较,只要比3大的就移位。最后遇到不大于3数时停止,把3插入。
在这里插入图片描述
在这里插入图片描述
代码实现:


private void insertSort(int[] array , int n) {
        int len = array.length;
        for (int i = 1 ; i < len ; i ++) {
            //把array[i]插入到前面合适位置
            int temp = array[i];
            int j;
            for (j = i ; j > 0 && array[j - 1] > temp ; j --) {
                array[j] = array[j - 1];
            }
            array[j] = temp;
        }
    }

遍历了n次数组,每一次都要把数据移动到正确位置,平均时间复杂度是O(n^2)。排序是稳定的。

4、总结

测试:编写一个随机产生n个元素的数组,并且计算三种算法对同一个数组的排序时间,比较各个算法性能。

产生数组和打印数组的方法:


private int[] generateRangeArray(int n , int rangeL , int rangeR) {
       int[] res = new int[n];
       for (int i = 0 ; i < n ; i ++)
           res[i] = (int)(Math.random()*(rangeR - rangeL + 1))+rangeL;
       return res;
   }

   //打印数组
   private void printArray(int[] array , int n) {
       int row = 0;
       for (int i = 0 ; i < n ; i ++) {
           System.out.print(array[i] + " ");
           row++;
           if (row%10 == 0)
               System.out.println();
       }
   }

性能比较:

 int n = 100000;
        int[] array = sort.generateRangeArray(n , 5 , n*10);
        //选择排序
        long startTimeSelectSort = System.nanoTime();
        sort.selectSort(selectArray, n);
        //sort.printArray(res , n);
        long endTimeSelectSort  = System.nanoTime();
        double timeSelectSort = (endTimeSelectSort - startTimeSelectSort)/1000000000.0;
        System.out.println("选择排序时间是:" + timeSelectSort + "s");

        //插入排序
        long startTimeInsertSort = System.nanoTime();
        sort.insertSort(insertArray , n);
        //sort.printArray(array , n);
        long endTimeInsertSort  = System.nanoTime();
        double timeInsertSort = (endTimeInsertSort - startTimeInsertSort)/1000000000.0;
        System.out.println("插入排序时间是:" + timeInsertSort + "s");

        //冒泡排序
        long startTimeBubbleSort = System.nanoTime();
        sort.bubbleSort(bubbleArray, n);
        //sort.printArray(array , n);
        long endTimeBubbleSort  = System.nanoTime();
        double timeBubbleSort = (endTimeBubbleSort - startTimeBubbleSort)/1000000000.0;
        System.out.println("冒泡排序时间是:" + timeBubbleSort + "s");

测试结果
在这里插入图片描述
虽然这三种算法都是O(n^2)级别,在100000个数据测试下,选择排序和冒泡排序慢的很多。选择排序每次都要完全遍历一遍未排序的数组,这样会耗时,而冒泡排序不仅也要遍历数组,还有不断交换位置,所以冒泡排序会更加耗时。但是优化后的插入排序会快很多,使用暂存当前值,找的合适位置再插入的方法,性能上提高很多。所以在O(nlogn)情况下,插入排序效果最好。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值