圖解選擇排序與插入排序

上一篇詳述了冒泡排序及其優化,有興趣的能夠看看:java

如何優化冒泡排序?算法

1、選擇排序(SelectionSort)

  • 算法思想:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,而後,再從剩餘未排序元素中繼續尋找最小(大)元素,而後放到已排序序列的末尾。以此類推,直到全部元素均排序完畢。
  • 排序過程:(默認升序)
  1. 從原序列中找到最小值,與數組第一個元素交換;
  2. 除第一個元素外,從剩下未排序的序列中找到最小值,與數組第二個元素交換;
  3. 共N-1趟,每趟都找到未排序的最小值,放到已排序的序列後面。

如圖所示,每一趟找到未排序的最小值,並放到有序序列的後面(即當前趟對應於數組中的第幾個元素)。數組

  • java實現選擇排序
 private static <T extends Comparable<? super T>> void selectionSort(T[] nums) {
        if (null == nums || nums.length == 0) {
            throw new RuntimeException("數組爲null或長度爲0");
        }
        int length = nums.length;
        int minValueIndex = 0;
        T temp = null;
        for (int i = 0; i < length - 1; i++) {
            minValueIndex = i;
            for (int j = i + 1; j < length; j++) {
                if (nums[j].compareTo(nums[minValueIndex]) < 0) {
                    minValueIndex = j;
                }
            }
            if (minValueIndex != i) {
                temp = nums[i];
                nums[i] = nums[minValueIndex];
                nums[minValueIndex] = temp;
            }
        }
    }
複製代碼
  • 時間、空間複雜度及穩定性分析:
  1. 最好時間複雜度:最好狀況是輸入序列已經升序排列,須要比較n*(n-1)/2次,但不須要交換元素,即交換次數爲:0;因此最好時間複雜度O(n^2)
  2. 最壞時間複雜度:最壞狀況是輸入序列是逆序的,則每一趟都須要交換。即須要比較n*(n-1)/2次,元素交換次數爲:n-1次。因此最壞時間複雜度仍是O(n^2)
  3. 平均時間複雜度:O(n^2)
  4. 空間複雜度:只用到一個臨時變量,因此空間複雜度O(1)
  5. 穩定性:不穩定排序。如序列3,5,3,1。第一次交換結果爲1,5,3,3,咱們發現原序列的第一個3排在了第二個3的後面。

2、插入排序(InsertSort)

  • 算法思想:經過構建有序序列,對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入。插入排序於是在從後向前掃描過程當中,須要反覆把已排序元素逐步向後挪位,爲最新元素提供插入空間。app

  • 排序過程:(默認升序)post

    InsertionSort 和打撲克牌時,從牌桌上逐一拿起撲克牌,在手上排序的進程相同。優化

    舉例:spa

    Input: {4, 3, 8, 5, 2, 6, 1, 7}。code

  1. 首先拿起第一張牌, 手上有 {4}。orm

  2. 拿起第二張牌 3, 把 3insert 到手上的牌 {4}, 獲得 {3 ,4}。cdn

  3. 拿起第三張牌 8, 把 8 insert 到手上的牌 {3,4 }, 獲得 {3 ,4,8}。

  4. 以此類推。

    插入排序由N-1趟排序組成。對於p=1到N-1趟排序後,插入排序保證從位置0到位置p上的元素爲已排序狀態。即插入排序利用了從位置0到p-1位置上已經有序的條件,將位置p上的元素向前查找適當的位置插入此元素。

    如圖所示:在第p趟,咱們將位置p上的元素向左移動,直到它在前p+1個元素(包括當前位置的元素)中的正確位置被找到。

  • java實現插入排序

    private static <T extends Comparable<? super T>> void insertSort(T[] nums) {
          if (null == nums || nums.length == 0) {
              throw new RuntimeException("數組爲null或長度爲0");
          }
          int length = nums.length;
          T temp = null;
          int i = 0;
          for (int p = 1; p < length; p++) {
              temp = nums[p];
              for (i = p; i > 0 && (temp.compareTo(nums[i - 1]) < 0); i--) {
                  nums[i] = nums[i - 1];
              }
              nums[i] = temp;
          }
      }
    複製代碼
  • 時間、空間複雜度及穩定性分析:

  1. 最好時間複雜度:最好狀況就是,序列已是升序排列了,在這種狀況下,須要進行的比較操做需n-1次便可。即最好時間複雜度O(n)
  2. 最壞時間複雜度:最壞狀況就是,序列是降序排列,那麼總共須要n(n-1)/2次比較;移動次數(賦值操做)是比較次數減去n-1次(由於每一次循環的比較都比賦值多一次,共n-1次循環),即n(n-1)/2 - (n-1);因此最壞時間複雜度O(n^2)
  3. 平均時間複雜度:O(n^2)
  4. 空間複雜度:只用到一個臨時變量,因此空間複雜度O(1)
  5. 穩定性:穩定。

3、總結

選擇排序的主要優勢與數據移動有關。若是某個元素位於正確的最終位置上,則它不會被移動。選擇排序每次交換一對元素,它們當中至少有一個將被移到其最終位置上,所以對n個元素的表進行排序總共進行n-1次交換。在全部的徹底依靠交換去移動元素的排序方法中,選擇排序屬於很是好的一種。選擇排序最好、最壞時間複雜度都爲O(n^2),空間複雜度爲O(1),屬於不穩定排序。

插入排序不適合對於數據量比較大的排序應用。可是,若是須要排序的數據量很小,例如,量級小於千;或者若已知輸入元素大體上按照順序排列,那麼插入排序仍是一個不錯的選擇。插入排序最好時間複雜度爲O(n)、最壞時間複雜度爲O(n^2),空間複雜度爲O(1),屬於穩定排序。

相關文章
相關標籤/搜索