簡單選擇排序演算法原理及java實現(超詳細)
阿新 • • 發佈:2018-12-14
選擇排序是一種非常簡單的排序演算法,就是在序列中依次選擇最大(或者最小)的數,並將其放到待排序的數列的起始位置。
也就是說,簡單選擇排序可分為兩部分,一部分是選擇待排序的數列中最小的一個數,另一部分是讓這個數與待排序的數列部分的第1個數進行交換,直到待排序的數列只有一個元素,至此整個數列有序。
這個演算法非常簡單,其排序過程如圖 1 所示。
圖 1 簡單選擇排序的排序過程
其中的方框部分為待排序的數列部分,雙下畫線的元素為待排序的數列中最小的元素,單下畫線的元素為待排序的數列的首元素,每一趟讓它們進行交換,最終得到有序數列。
簡單選擇排序的實現程式碼如下:
通過程式碼,我們發現這個演算法其實挺爛的,而且應該有可以優化的方法,這裡先賣個關子。測試程式碼如下:
在最好的情況下,每次要找的最大(或者最小)的元素就是待排序的數列的第1個元素,也就是說數列本身有序,這樣我們只需要一次遍歷且不需要交換,即可實現一趟排序;而在最壞的情況下,每次在數列中要找的元素都不是第 1 個元素,每次需要交換。比較的次數只與數列的長度有關,而在外部要遍歷整個數列,也與長度有關,所以這樣的雙重迴圈不管在什麼情況下,時間複雜度都是
但由於選擇排序不需要一個一個地向前移動,而是直接交換,而比較所消耗的 CPU 要比交換所消耗的 CPU 小一些,所以選擇排序的時間複雜度相對於氣泡排序會好一些。
在穩定性方面,對於數列 6、6、1 來說,首先需要找到最小的一個元素與第 1 個元素進行交換,這時數列變為 1、6、6,我們發現兩個 6 的順序已經變了,所以選擇排序是一個不穩定的排序演算法。
另外,我們每次都要尋找兩個值中一個是最大值,一個是最小值。這時如果需要將數列從小到大排列,就要把最小值與待排序的數列的第1個元素進行交換,把最大值與待排序的數列的最後一個元素進行交換。這樣我們一次就能尋找兩個元素,使外層迴圈的時間縮短了一半,效能也提高了很多。而且通過一次遍歷就可以直接找出兩個最值,並沒有其他效能損耗。這種一次找兩個值的選擇排序的演算法實現,留給讀者自己去嘗試。
簡單選擇排序的原理
簡單選擇排序的原理非常簡單,即在待排序的數列中尋找最大(或者最小)的一個數,與第 1 個元素進行交換,接著在剩餘的待排序的數列中繼續找最大(最小)的一個數,與第 2 個元素交換。以此類推,一直到待排序的數列中只有一個元素時為止。也就是說,簡單選擇排序可分為兩部分,一部分是選擇待排序的數列中最小的一個數,另一部分是讓這個數與待排序的數列部分的第1個數進行交換,直到待排序的數列只有一個元素,至此整個數列有序。
這個演算法非常簡單,其排序過程如圖 1 所示。
圖 1 簡單選擇排序的排序過程
其中的方框部分為待排序的數列部分,雙下畫線的元素為待排序的數列中最小的元素,單下畫線的元素為待排序的數列的首元素,每一趟讓它們進行交換,最終得到有序數列。
簡單選擇排序的實現
public class SelectSort { private int[] array; public SelectSort(int[] array) { this.array = array; } public void sort() { int length = array.length; for (int i = 0; i < length; i++) { int minIndex = i; for (int j = i + 1; j < array.length; j++) { if (array[j] < array[minIndex]) { minIndex = j; } } if (minIndex != i) { int temp = array[minIndex]; array[minIndex] = array[i]; array[i] = temp; } } } public void print() { for (int i = 0; i < array.length; i++) { System.out.println(array[i]); } } }
public class SortTest { public static void main(String[] args) { testSelectSort(); } /** * 簡單選擇排序 */ private static void testSelectSort() { int[] array = {5, 9, 1, 9, 5, 3, 7, 6, 1}; SelectSort selectSort = new SelectSort(array); selectSort.sort(); selectSort.print(); } }
選擇排序的特點及效能
由於在簡單選擇排序中,我們一般在原本的待排序的陣列上排序並交換,基本上使用的都是常量級的額外空間,所以其空間複雜度是O(1)
。在最好的情況下,每次要找的最大(或者最小)的元素就是待排序的數列的第1個元素,也就是說數列本身有序,這樣我們只需要一次遍歷且不需要交換,即可實現一趟排序;而在最壞的情況下,每次在數列中要找的元素都不是第 1 個元素,每次需要交換。比較的次數只與數列的長度有關,而在外部要遍歷整個數列,也與長度有關,所以這樣的雙重迴圈不管在什麼情況下,時間複雜度都是
O(n2)
。但由於選擇排序不需要一個一個地向前移動,而是直接交換,而比較所消耗的 CPU 要比交換所消耗的 CPU 小一些,所以選擇排序的時間複雜度相對於氣泡排序會好一些。
在穩定性方面,對於數列 6、6、1 來說,首先需要找到最小的一個元素與第 1 個元素進行交換,這時數列變為 1、6、6,我們發現兩個 6 的順序已經變了,所以選擇排序是一個不穩定的排序演算法。
簡單選擇排序的優化
通過選擇排序的思想,我們知道選擇排序的一個重要步驟是在待排序的數列中尋找最大(或者最小)的一個元素,那麼如何尋找這個元素就成為一個可以優化的點。另外,我們每次都要尋找兩個值中一個是最大值,一個是最小值。這時如果需要將數列從小到大排列,就要把最小值與待排序的數列的第1個元素進行交換,把最大值與待排序的數列的最後一個元素進行交換。這樣我們一次就能尋找兩個元素,使外層迴圈的時間縮短了一半,效能也提高了很多。而且通過一次遍歷就可以直接找出兩個最值,並沒有其他效能損耗。這種一次找兩個值的選擇排序的演算法實現,留給讀者自己去嘗試。