選擇排序的原理
選擇排序的原理是首先取第一個數字作為數組中的最小者minValue(以升序排序為例),依次跟后續數字進行比較,如果發現有比minValue更小的數字,記錄該數字的下標,並將該數字的值賦給minValue,直到遍歷完數組的最后一個數字。然后根據記錄的實際最小值的下標,跟第一個數字進行交換。
第一趟比較執行完后就找到了數組中最小者,然后再從下一個數字開始,重復執行前面的步驟,直到倒數第二個數字比較完為止(最后數字無需比較即為最大數字)
圖解選擇排序過程
假設要排列的數字為 3 1 4 2 ,當進行第一趟排序時,如下圖所示(其中i表示數組的下標)
第一趟排序后,數組中最小的數字1已找到並放置在第0位置。下面看第二趟比較,如下圖所示。
第二趟比較從第二個數開始,將minIndex設置為1,並將minValue設置為4。並依次跟后面的數比較,發現3<4,將minIndex和minValue修改為對應值。繼續向后比較發現2<3,將minIndex和minValue修改為對應值。第二趟遍歷結束,將第1位置的值設置為minIndex對應的值2,並將minIndex值設置為4。第二趟比較結束。繼續執行第三趟排序(雖然我們看到現在數組已經有序,但程序不知道)。第三趟比較如下圖所示
第三趟比較時,將minIndex設置為2,minValue設置為3。依次向后比較,4>3不改變minIndex和minValue。遍歷結束,無需進行交換(通過趟數值與minIndex值是否相等來判斷是否需要交換)
代碼實現
1 public static void sort(int array[]){ 2 //第一個for循環表示要進行length-1次選擇 3 for (int i = 0; i < array.length - 1; i++) { 4 int minIndex = i; 5 int minValue = array[minIndex]; 6 for (int j= i+1; j<array.length; j++){ 7 if(minValue > array[j]){ 8 minIndex = j; 9 minValue = array[j]; 10 } 11 } 12 //執行完一輪選擇后進行交換(如果最小值下標有改變才進行交換) 13 if(minIndex != i){ 14 array[minIndex] = array[i]; 15 array[i] = minValue; 16 } 17 } 18 }
代碼分析
1)第一層for循環確定比較趟數,通過我們的分析,比較n-1趟即可(n為數組長度)
2)第二層for循環用於遍歷所選擇的最小值后續數字,比較是否有小於所選擇的最小值,如果有,則修改minIndex和minValue
3)if提交判斷,用於判定minIndex是否被修改過,如果沒有修改過,則無需交換(否則自己與自己交換,無意義)
時間復雜度
選擇排序有兩層for循環,所示時間復雜度為T(n)=O^2
測試執行時間
與上一篇冒泡排序相同,依然生成10萬個數字進行排序。代碼如下
1 public static void main(String []args){ 2 int array[] = new int[100000]; 3 for (int i = 0; i < 100000; i++) { 4 array[i] = (int) (Math.random()*1000000); 5 } 6 long begin = System.currentTimeMillis(); 7 sort(array); 8 System.out.println("總耗時="+(System.currentTimeMillis()-begin)); 9 }
執行結果(單位為毫秒)
可以看出,在我的機器上使用選擇排序對10萬個數字的數組進行排序,大概需要3秒多的時間,比冒泡排序的17秒快了很多。下一篇我將講解插入排序的過程,耗時會不會更小呢?一起期待!!!
總結
選擇排序需要注意兩點,一是比較的趟數,有n個數,比較n-1即可。二是每趟比較,都認為當前數為最小(或最大)值,然后依次跟后面數字比較,如果發現有比我們假設的最小值更小,則改變成新的下標和新的最小值繼續向后比較,直到遍歷完所有數字。如果假設的最小值下標有修改則進行交換。