关于算法:排序算法学习1简单排序

46次阅读

共计 2837 个字符,预计需要花费 8 分钟才能阅读完成。

抉择排序

抉择排序 (Selection Sort) 是一种十分简单明了的排序算法,其基本思路是:假如一个数组有 n 个数,从第一个数开始,遍历一遍找到最小的一个数的下标,将最小的数与第一个数替换地位,这样第一个数的地位就排好了,接下来从第二个数开始遍历找到从 2 到 n 中最小的数与第二个数做替换,如此重复,晓得第 n-1 个数也排好序了,整个数组排序就完结了。

示意图

代码示例:

public class SelectionSort {public static void sort(int[] arr) {for (int i = 0; i < arr.length - 1; i++) {
            int mini = i;
            for (int j = i+1; j < arr.length; j++) {if(arr[j] < arr[mini]) {mini = j;}
            }
            swap(arr, i, mini);
        }
    }
}

工夫复杂度和空间复杂度

算法第一次循环执行 n-1 次,第二次循环执行 n-2 次,以此类推,直到排序实现大概执行了 (n-1) + (n-2) + ... + 2 + 1,这是一个等差数列,依据等差数列公式能够得出执行了 $\frac{n^2}{2} – \frac{n}{2}$ 次,疏忽常数项和低次项失去工夫复杂度 $O(n^2)$

依据算法的计算过程,能够晓得不论是什么数组都要执行 $\frac{n^2}{2} – \frac{n}{2}$,其最好和最差的状况下工夫复杂度都是 $O(n^2)$

算法除开一些长期变量并没有应用一些额定空间,因而空间复杂度是 $O(1)$

稳定性

因为算法是间接将数组中找到的最初一个最小的数与第一个数替换,因而相等的两个数的程序会在替换之后扭转,所以抉择排序是一个不稳固的排序算法

优化

在一次循环遍历中同时找到最大和最小值,别离与最初一位和第一位数进行替换,缩小循环的次数。尽管如此,其工夫复杂度任然是 $O(n^2)$

代码示例:

public static void sort(int[] arr) {
     int len = arr.length;
     for (int i = 0; i < len/2; i++) {
        int mini = i;
        int maxi = i;
        for (int j = i + 1; j < len-i; j++) {if (arr[j] < arr[mini]) {mini = j;}
            if (arr[j] > arr[maxi]) {maxi = j;}
        }
        swap(arr, i, mini);
        // 留神在最大值替换前有可能曾经被最小值替换
        if (maxi == i) {maxi = mini;}
        swap(arr, len-1 - i, maxi);
    }
}

冒泡排序

冒泡排序也是简略排序的一种,其算法思路是:假如一个数组的长度为 n,比拟第一个数和第二个数,若第一个数大于第二个数,替换两个数,再比拟第二个数与第三个数的大小,大于则替换,同样地比拟剩下的数,最初,最大的数将会到数组开端,第 n 个数曾经排好序了,再对 1 ~ n-1 的数做雷同操作,1 ~ n-1 中最大的数会到 n-1 的地位,n-1 ~ n 是排好序的,反复这个 “ 冒泡 ” 过程,直到排序(若一次循环中未产生过一次替换能够提前结束排序)。

示意图

如上图所示,5 8 排好序之后,剩下的 1 3 4 进行排序,同样的一次循环后将不会产生替换,阐明剩下局部曾经有序,此时能够提前结束排序。

代码示例

public class BubbleSort {public static void sort(int[] arr) {for (int i = arr.length; i > 1; i--) {
            boolean flag = true;
            for (int j = 1; j < i; j++) {if (arr[j-1] > arr[j]) {swap(arr, j-1, j);
                    flag = false;
                }
            }
            if (flag) {break;}
        }
    }
}

工夫复杂度和空间复杂度

冒泡排序在个别状况下,须要进行两层嵌套循环,第一次循环执行 n-1 次,第二次执行 n-2 次 …,直到最初大概执行了 (n-1) + (n-2) + ... + 2 + 1,同样是等差数列,因而工夫复杂度为 $O(n^2)$。最差状况下其工夫复杂度为 $O(n^2)$,而如果程序中做了优化,在未产生替换时提前结束排序,则只需执行一次循环,所以最好状况的工夫复杂度是 $O(n)$。

因为除了局部长期变量外,没有用到其余额定空间,所以其空间复杂度为 $O(1)$。

稳定性

在冒泡排序算法中,相邻两个数进行比拟时,相等的数将不会进行替换,因而能够保障相等的数在排序后的程序不变,是一种稳固的排序算法。

插入排序

插入排序是简略排序中的最初一种,插入排序顾名思义,相似于持有一手乱序的扑克牌,每次从无序的牌中取出一张插入有序的牌中,随着无序的牌组缩小,整副牌趋于有序。其基本思路是:假如数组长度为 n,从第二个数开始,同前一个数进行比拟,若小于前一个数则替换,否则进行插入,再从第三个数开始往前面曾经有序的局部插入,反复这个步骤,直到最初一个数插入实现,数组有序。

示意图

代码示例

public class InsertSort {public static void sort(int[] arr) {for (int i = 1; i < arr.length; i++) {for (int j = i; j > 0 && arr[j] < arr[j-1]; j--) {swap(arr, j, j-1);
            }
        }
    }
}

下面的代码须要每次进行替换,能够稍加改良:

public class InsertSort {public static void sort(int[] arr) {for (int i = 1; i < arr.length; i++) {
            int j = i;
            int temp = arr[j];
            while (j > 0 && temp < arr[j-1]) {arr[j] = arr[j-1];
                j--;
            }
            arr[j] = temp;
        }
    }
}

工夫复杂度和空间复杂度

插入排序算法同样的应用到了嵌套循环,个别状况下整个算法大概执行了 1 + 2 + ... + (n-2) + (n-1),同样的工夫复杂度是 $O(n^2)$,然而插入排序要比冒泡排序少了许多比拟和替换的过程,会快得多,而且在比拟有序的状况下,所用的工夫会比拟少,最好的状况下只需循环一次,因而最好工夫复杂度为 $O(n)$。

同样的插入排序的空间复杂度为 $O(1)$。

稳定性

插入排序通过比拟相邻元素的大小进行替换,因而同样是稳固的。

总结

三种简略排序算法的工夫复杂度都是 $O(n^2)$,空间复杂度是 $O(1)$,冒泡排序和插入排序和插入排序的最好工夫复杂度是 $O(n)$,是稳固排序,抉择排序的最好工夫复杂度是 $O(n^2)$,是不稳固排序,同时插入排序要比冒泡排序快一些,因而在数据量小时能够应用简略排序,优先应用插入排序。

正文完
 0