演算法主要衡量標準
時間複雜度(執行時間)
在演算法時間複雜度維度,我們主要對比較和交換的次數做對比,其他不交換元素的演算法,主要會以訪問陣列的次數的維度做對比。
其實有很多同學對於演算法的時間複雜度有點模糊,分不清什麼所謂的 O(n),O(nlogn),O(logn)...等,也許下圖對一些人有一些更直觀的認識。
空間複雜度(額外的記憶體使用)排序演算法的額外記憶體開銷和執行時間同等重要。 就算一個演算法時間複雜度比較優秀,空間複雜度非常差,使用的額外記憶體非常大,菜菜認為它也算不上一個優秀的演算法。
結果的正確性
原理這個指標是菜菜自己加上的,我始終認為一個優秀的演算法最終得到的結果必須是正確的。就算一個演算法擁有非常優秀的時間和空間複雜度,但是結果不正確,又有什麼意義呢?
在起始位置右側(或左側)找出最小的那個元素,然後和起始位置的元素交換。
選擇排序是一個不穩定的排序演算法。
具體步驟如下:
1. 在一個數據列表中找到最小的那個元素,將它和列表的第一個元素交換位置。
2. 在第二個元素位置開始再次尋找最小的那個元素,然後和列表的第二個位置的元素交換。
3. 在第三個元素位置開始再次尋找最小的那個元素,然後和列表的第三個位置的元素交換
4. 如此反覆,直到開始查詢起始位置到達列表末尾。
如果查詢過程中最小的元素就是起止位置的元素,那麼它就和它自己交換。
因為這種演算法總是在不斷的選擇剩餘元素中最小者,因此得名選擇排序
複雜度時間複雜度
1. 比較次數
對於長度為N的列表,選擇排序需要大約n² /2次比較.即:O(n²)平方級別。
2. 交換次數
效能和特點對於長度為N的列表,選擇排序需要大約N次交換.即:O(N) 線性級別。
總體來說,選擇排序是一種比較簡單的排序演算法,很容易理解也很好用程式碼實現,當然他的特點也很明顯:
執行時間和資料初始狀態無關
為什麼這麼說呢?演算法進行中為了查詢最小的元素而遍歷列表並不能為下次遍歷帶來任何資訊,這個特性在大部分情況下是缺點。如果一個數據列表初始狀態是有序的或者部分有序的,選擇排序仍然需要全部掃描一次和交換。因此和一個完全無序的列表排序所花的時間相差不大。
資料移動次數是最少的
每次交換隻會改變兩個列表元素,因此長度為N的列表只會發生N次交換,交換次數和列表的長度是線性關係,其他演算法都不具備這個特性。
適用場景由於選擇排序的對比次數在平方級別,但是移動次數線上性級別,所以當N比較小的時候比較適用。
其他為什麼選擇排序不穩定呢?
首先我們要明白演算法穩定是什麼意思呢?
在待排序的資料中,存在多個相同的資料,經過排序之後,他們的相對順序依舊保持不變,實際上就是說array[i]=array[j],i<j.就是array[i]在array[j]之前,那麼經過排序之後array[i]依舊在array[j]之前,那麼這個排序演算法穩定,否則,這個排序演算法不穩定。
根據以上定義很容易可以得出這樣的結論:
實現案例我們舉出一個例項,序列5 8 5 2 9, 這個在執行選擇排序的時候,第一遍,肯定會將array[0]=5,交換到2所在的位置,也就是 2 8 5 5 9,那麼很顯然,之後的排序我們就會發現,array[2]中的5會出現在原先的array[0]之前,所以選擇排序不是一個穩定的排序
static void Main(string[] args) { List<int> data = new List<int>() ; for (int i = 0; i < 10; i++) { data.Add(new Random(Guid.NewGuid().GetHashCode()).Next(1, 100)); } //列印原始陣列值 Console.WriteLine($"原始資料: {string.Join(",", data)}"); int n = data.Count; for (int i = 0; i < n; i++) { int minIndex = i; //查詢最小的元素的索引 for (int j = i+1; j < n; j++) { if (data[j] < data[minIndex]) { minIndex = j; } } //交換最小的元素和當前位置的元素,當然這裡可以加入一個最小元素是否是當前位置元素的判斷來較少交換次數 int tempItem = data[i]; data[i] = data[minIndex]; data[minIndex] = tempItem; } //列印排序後的陣列 Console.WriteLine($"排序資料: {string.Join(",", data)}"); Console.Read(); }
執行結果: