1. 程式人生 > >資料結構與算法系列十三(選擇排序)

資料結構與算法系列十三(選擇排序)

1.引子

1.1.為什麼要學習資料結構與演算法?

有人說,資料結構與演算法,計算機網路,與作業系統都一樣,脫離日常開發,除了面試這輩子可能都用不到呀!

有人說,我是做業務開發的,只要熟練API,熟練框架,熟練各種中介軟體,寫的程式碼不也能“飛”起來嗎?

於是問題來了:為什麼還要學習資料結構與演算法呢?

#理由一:
    面試的時候,千萬不要被資料結構與演算法拖了後腿
#理由二:
    你真的願意做一輩子CRUD Boy嗎
#理由三:
    不想寫出開源框架,中介軟體的工程師,不是好廚子

1.2.如何系統化學習資料結構與演算法?

我想好了,還是需要學習資料結構與演算法。但是我有兩個困惑:

1.如何著手學習呢?

2.有哪些內容要學習呢?

學習方法推薦:

#學習方法
1.從基礎開始,系統化學習
2.多動手,每一種資料結構與演算法,都自己用程式碼實現出來
3.思路更重要:理解實現思想,不要背程式碼
4.與日常開發結合,對應應用場景

學習內容推薦:

資料結構與演算法內容比較多,我們本著實用原則,學習經典的、常用的資料結構、與常用演算法

#學習內容:
1.資料結構的定義
2.演算法的定義
3.複雜度分析
4.常用資料結構
    陣列、連結串列、棧、佇列
    散列表、二叉樹、堆
    跳錶、圖
5.常用演算法
    遞迴、排序、二分查詢
    搜尋、雜湊、貪心、分治
    動態規劃、字串匹配

2.考考你

上一篇:資料結構與算法系列十二(插入排序)中,我們詳細分析了插入排序的核心思想,和程式碼實現。插入排序的核心思想很巧妙:它是將待排序序列,分為有序區間,和無序區間,迴圈遍歷無序區間,每一次將無序區間中的第一個元素,插入到有序區間的合適位置,每一次插入都要始終保證有序區間有序。

你需要對插入排序的核心思想再仔細琢磨一下,因為我們今天的主角:選擇排序,它的核心思想與插入排序類似。

#考考你:
1.你知道選擇排序的核心思想嗎?
2.你能用java程式碼實現選擇排序嗎?
3.你知道實際開發中,為什麼插入排序,比選擇排序更好嗎?

3.案例

3.1.選擇排序核心思想

假設有一個待排序序列:[4, 5, 6, 3, 2, 1]。我們需要按照升序進行排序,排序後的序列是這 樣的:[1, 2, 3, 4, 5, 6]。

如何通過選擇排序實現呢?

選擇排序核心思想:

將待排序序列,分成兩個區間:有序區間、無序區間。一開始假定有序區間元素個數:0,無序區間元素個數:n。迴圈遍歷無序區間,每一次從無序區間中,選擇最小的一個元素,插入到有序區間的末尾。

這裡的關鍵詞有:

1.待排序序列,分成:有序區間、無序區間
2.最開始,假定有序區間元素個數:0,無序區間元素個數:n
3.每次迴圈遍歷無序區間,選擇最小元素,插入到有序區間末尾,如下圖:

 

 

3.2.選擇排序程式碼實現

3.2.1.排序程式碼

/**
* 選擇排序
* @param array:待排序陣列
* @param n:待排序陣列大小
*/
public static void sort(Integer [] array,int n) {
   // 如果排序陣列規模小於等於1,直接返回
   if (n <= 1) {
       return;
   }

   // 將待排序陣列,分為:有序區間、無序區間
   // 一開始,假設整個序列都無序,那麼有序區間的元素個數是:0
   // 無序區間的元素個數是:n
   // 每次從無序區間中,選擇最小元素
   // 插入有序區間末尾:n個元素,n次選擇
   for(int i = 0; i < n; i++){

      // 從無序區間第一個位置開始查詢:最小元素位置
      int min = i;
      for(int j = i+1; j < n; j++){
        // 比較大小,設定新的最小元素位置標記
        if(array[min] > array[j]){
             min = j;
         }
      }

     // 找到新的最小元素位置後,進行資料交換
    System.out.println("第【"+(i+1)+"】次選擇,最小元素是:"+array[min]);
    int tmp = array[i];
    array[i] = array[min];
    array[min] = tmp;

   }

}

3.2.2.測試程式碼

/**
 * 選擇排序:
 * 1.時間複雜度:
 *      O(n^2)
 *  2.空間複雜度:
 *      O(1)是原地排序演算法
 * 3.演算法穩定性:
 *     不是穩定排序演算法
 */
public static void main(String[] args) {
   // 初始化測試陣列
   Integer[] array = {4,5,6,3,2,1};
   // 排序前
   System.out.println("1.排序前陣列:" + Arrays.deepToString(array));

   // 排序
   System.out.println("2.開始排序-------------------------------start");
   sort(array,array.length);

   // 排序後
   System.out.println("3.排序後陣列:" + Arrays.deepToString(array));
 }

測試結果:

D:\02teach\01soft\jdk8\bin\java 
    com.anan.algorithm.sort.SelectSort
1.排序前陣列:[4, 5, 6, 3, 2, 1]
2.開始排序-------------------------------start
第【1】次選擇,最小元素是:1
第【2】次選擇,最小元素是:2
第【3】次選擇,最小元素是:3
第【4】次選擇,最小元素是:4
第【5】次選擇,最小元素是:5
第【6】次選擇,最小元素是:6
3.排序後陣列:[1, 2, 3, 4, 5, 6]

Process finished with exit code 0

4.討論分享

#考考你答案:
1.你知道選擇排序的核心思想嗎?
  1.1.將待排序序列,分成:有序區間、無序區間
  1.2.最開始,有序區間元素個數:0,無序區間元素個數:n
  1.3.迴圈遍歷無序區間,每次選擇最小元素,插入有序區間末尾
  
2.你能用java程式碼實現選擇排序嗎?
  2.1.參考【3.2】節程式碼實現
  
3.你知道實際開發中,為什麼插入排序,比選擇排序更好嗎?
  3.1.我們在排序演算法概述中說過,衡量一個排序演算法的優劣,
  有三個因素:時間複雜度、空間複雜度、是否穩定
  3.2.插入排序與選擇排序,它們的時間複雜度都是:O(n^2)
  3.3.插入排序與選擇排序,它們的空間複雜度都是:O(1)
  3.3.插入排序,是穩定的排序演算法
  
  3.4.【注意】:選擇排序,不是穩定排序演算法
  3.5.假設有一個待排序序列:int a[]={4,5,6,4,3,2,1}
  3.6.待排序序列中,有重複元素:a[0]=4,a[3]=4
  3.7.第一輪選擇排序,選擇最小元素:a[6]=1
  3.8.將a[0]=4,a[6]=1進行交換
  
  3.9.【注意】:第一輪選擇排序後,重複元素4的順序發生了改變
  3.10.待排序序列變成:a[]={1,5,6,4,3,2,4}
  3.11.此時重複元素:a[3]=4,a[6]=4
  3.12.a[3]還是原來的a[3],a[6]是原來的a[0]
  
  3.13.我們說穩定排序演算法,是指待排序序列中重複元素,
  排序前的順序,與排序後的順序保持不變
  3.14.可見選擇排序,不符合穩定排序演算法的定義
  3.15.關於選擇排序,不是穩定排序演算法的分析,你可以結合我們前面的圖來理解

&n