美文网首页
冒泡、插入、选择

冒泡、插入、选择

作者: Rreply | 来源:发表于2019-01-16 23:47 被阅读7次

    插入排序和冒泡排序的时间复杂度都是O(n^2),但是为什么实际使用上,我们更加倾向于使用插入排序呢?

    如何分析一个“排序算法”?

    需要从以下三个方面来考虑。

    • 算法的执行效率
      1. 最好、最坏、平均时间复杂度
      2. 时间复杂度的常数、系数、低阶
      3. 比较次数和交换(或移动)次数
    • 排序算法的内存消耗
    • 排序算法的稳定性

    首先从算法的执行效率方面来说:

    1. 有时候我们为了更好地对算法的优劣进行排序对比,需要将其三种时间复杂度都计算出来。
    2. 我们用来计算的数据有时候就是有序的或者逆序的,这个时候就必须使用最好或者最坏时间复杂度来进行对比。
    3. 虽然我们平时会忽略掉常数、系数、低阶,但是如果我们进行计算的数据并不是特别大,就不应该忽略它们。例如O(n) +20,在n不大的情况下,常数项就必须纳入考虑范围内了。
    4. 一般情况下我们忽略这些操作,但是对于冒泡、插入、选择来说,它们是基于比较的算法,所以比较和交换就不能够被忽略。

    然后从算法的内存消耗上来说:
    内存消耗也可以理解成为空间复杂度,对于这三种算法来说,他们的都是原地排序算法,所以其空间复杂度为O(1)。但是对于其他非原地排序的算法来说,是否需要牺牲空间来换取时间效率就成为一个重要的考量因素。
    最后从算法的稳定性来说:
    可能有一些人觉得算法稳定性并没有多大多用,但是举个例子,如果双十一,老板要求我们按照价格和时间的顺序把商品排好。有两种方法,一种就是先按照价格排序,然后同一价格再按照时间排序。还有一种方法就是使用稳定的算法先用时间排序,然后价格排序。

    有个APP叫数据结构和算法教程能够很好的展示这三种排序动画,所以就只给出源码了。

    冒泡排序

    import java.util.Arrays;
    
    public class BubbleSort {
    
        TestItem[] array;
    
        BubbleSort(TestItem[] array) {
            this.array = array;
        }
    
        boolean sort() {
            if (array.length == 0 || array.length == 1) {
                return false;
            }
    
            for (int i = 0; i < array.length - 1; i++) {
                for (int j = 0; j < array.length - 1 - i; j++) {
                    if (array[j].num > array[j + 1].num) {
                        TestItem temp = array[j + 1];
                        array[j + 1] = array[j];
                        array[j] = temp;
                    }
                }
            }
            return true;
        }
    
        public static void main(String[] args) {
            TestItem[] test = new TestItem[30];
            for (int i = 0; i < 30; i++) {
                test[i] = new TestItem(Math.random() * 10);
            }
            BubbleSort bubbleSort = new BubbleSort(test);
            bubbleSort.sort();
            System.out.println(Arrays.toString(bubbleSort.array));
    
        }
    
        static class TestItem {
    
            double num;
    
            TestItem(double a) {
                num = a;
            }
    
            @Override
            public String toString() {
                return "num为: " + num;
            }
        }
    }
    

    选择排序

    public class SelectSort {
    
        int[] array;
    
        SelectSort(int[] array){
            this.array = array;
        }
    
        boolean sort(){
            if (array.length == 0 || array.length ==1){
                return false;
            }
            for (int i = 0; i < array.length - 1; i++) {
                for (int j = i + 1; j < array.length; j++) {
                    if (array[i] > array[j]){
                        int temp = array[i];
                        array[i] = array[j];
                        array[j] = temp;
                        j++;
                    }
                }
            }
            return true;
        }
    }
    

    插入排序

    import java.util.Arrays;
    
    public class InsertSort {
    
        int[] array;
    
        InsertSort(int[] array){
            this.array = array;
        }
    
        boolean sort(){
            if (array.length == 0 || array.length == 1){
                return false;
            }
            for (int i = 1; i < array.length; i++) {
                if (array[i] < array[i -1]){
                    int temp = array[i];
                    for (int j = i-1; j >= 0 ; j--) {
                        if (array[j] > temp){
                            array[j + 1] = array[j];
                        } else {
                            array[j] = temp;
                            break;
                        }
                    }
                }
            }
            return true;
        }
    
        public static void main(String[] args) {
            int[] array = {1, 2,1,312,4234,2,41,3,123,1,31,312,3,123,1,31,3,131,3,};
            InsertSort sort = new InsertSort(array);
            sort.sort();
            System.out.println(Arrays.toString(sort.array));
        }
    }
    

    三个算法的比较

    排序算法 冒泡排序 选择排序 插入排序
    最好时间复杂度 O(n) O(n^2) O(n)
    最坏时间复杂度 O(n^2) O(n^2) O(n^2)
    平均时间复杂度(使用逆序度计算) O(n^2) O(n^2) O(n^2)
    是否稳定
    是否是原地排序(空间复杂度O(1)

    回到开题,为什么我们倾向于使用插入排序而不是冒泡排序呢?从表上来看,两种排序的时间复杂度都是一样的啊。
    请看下面对比

    //冒泡排序
    for (int i = 0; i < array.length - 1; i++) {
                for (int j = 0; j < array.length - 1 - i; j++) {
                    if (array[j].num > array[j + 1].num) {
                        //每次循环需要执行下面三行代码
                        TestItem temp = array[j + 1];
                        array[j + 1] = array[j];
                        array[j] = temp;
                    }
                }
            }
    //插入排序
     for (int i = 1; i < array.length; i++) {
                if (array[i] < array[i -1]){
                    int temp = array[i];
                    for (int j = i-1; j >= 0 ; j--) {
                        if (array[j] > temp){
                            //每次循环只需要执行一次代码
                            array[j + 1] = array[j];
                        } else {
                            array[j] = temp;
                            break;
                        }
                    }
                }
            }
    

    如果不把比较计算在内的话,冒泡比插入需要多消耗两倍的时间,考虑比较的话,需要多消耗一倍的时间,所以这也就是我们为什么使用插入而不是冒泡的原因了。

    相关文章

      网友评论

          本文标题:冒泡、插入、选择

          本文链接:https://www.haomeiwen.com/subject/plcvdqtx.html