冒泡排序(BubbleSort)算法:比較相鄰元素的大小,若是第一個元素大於第二個元素,則交換它們的位置,而後第二個元素與第三個元素比較,直到全部的元素比較完,冒泡出最小的元素。假設咱們有n各元素,那麼咱們就要進行 n-1 次冒泡,n-1 個最小的元素已經冒泡出來,所以,最後剩下的一個元素也就處於它應當處於的位置。算法
本篇文章主要是對冒泡排序進行優化,使其避免沒必要要的比較,以及泛型的實現,共分四個版本。優化
先來看一張直觀的圖:spa
static int FirstVersionBubbleSort(int[] array) { int count = array.Length - 1; int number = 0; for (int i = 0; i < count; i++) { for (int j = 0; j < count - i; j++) { if (array[j] > array[j + 1]) { int temp = array[j]; array[j] = array[j + 1]; array[j + 1] = temp; } number++; } } return number; }
外層循環用來控制冒泡的次數,內層循環用來比較相鄰元素的大小。number 用來記錄總共進行了幾回比較,爲後面的優化版本作對比。code
執行 Main():blog
int[] firstArray = { 2, 1, 3, 4 }; Console.WriteLine("總共比較的次數:{0}", FirstVersionBubbleSort(firstArray)); foreach (var item in firstArray) { Console.Write(item.ToString().PadRight(2)); }
總共比較的次數:6 1 2 3 4
總共比較了6次,分別是:排序
第一次冒泡出 4:繼承
2-1:1 2 3 4string
2-3:1 2 3 4it
3-4 : 1 2 3 4io
第二次冒泡 3:
1-2 : 1 2 3 4
2-3 : 1 2 3 4
第三次冒泡 2:
1-2 : 1 2 3 4
看一下上面的過程,就很容想到,當整個數列已經排好序後咱們就沒有必要再作多餘的比較。用一個標誌量來表示上次是否內層循環是否有元素交換,若是有則進行下一次循環,不然退出,由於全部元素已經有序。
static int SecondVersionBubbleSort(int[] array) { int count = array.Length; bool change; int number = 0; do { count--; change = false; for(int i = 0; i < count; i++) { if(array[i] > array[i + 1]) { int temp = array[i]; array[i] = array[i + 1]; array[i + 1] = temp; change = true; } number++; } }while(change); return number; }
執行Main():
int[] secondArray= { 2, 1, 3, 4 }; Console.WriteLine("\n總共比較的次數:{0}", SecondVersionBubbleSort(secondArray)); foreach (var item in secondArray) { Console.Write(item.ToString().PadRight(2)); }
總共比較的次數:5 1 2 3 4
總共比較了5次,分別是:
第一次冒泡出 4:
2-1:1 2 3 4
2-3:1 2 3 4
3-4 : 1 2 3 4
此時 change 爲 true
第二次冒泡 3:
1-2 : 1 2 3 4
2-3 : 1 2 3 4
發現已經有序,change 爲 false, 結束冒泡。再繼續思考,事實上,第一次冒泡後,二、三、4 已經有序,所以下次循環徹底沒有必要再繼續對其比較;如今咱們增長一個位置變量來記錄每次冒泡的最後交換的位置,下次比較的此處就能夠了,避免對後面已經有序的元素重複進行比較。
static int ThirdVersionBubbleSort(int[] array) { int count = array.Length - 1, index = 0; bool change; int number = 0; do { change = false; for (int i = 0; i < count; i++) { if (array[i] > array[i + 1]) { int temp = array[i]; array[i] = array[i + 1]; array[i + 1] = temp; change = true; index = i; // 記錄最後一次交換的位置 } number++; } count = index; } while (change); return number; }
執行 Main():
int[] thirdArray = { 2, 1, 3, 4 }; Console.WriteLine("\n總共比較的次數:{0}", ThirdVersionBubbleSort(thirdArray)); foreach (var item in thirdArray) { Console.Write(item.ToString().PadRight(2)); }
總共比較的次數:3 1 2 3 4
有上面的結果,能夠看到,此次只進行了 3 次比較,分別以下:
總共比較了3次,分別是:
第一次冒泡出 4:
2-1:1 2 3 4
2-3:1 2 3 4
3-4 : 1 2 3 4
此時 index 爲 0, count 爲 0,結束冒泡。可見,這種方式,能夠大大下降比較的次數。
若是說繼承是爲咱們提供了代碼重用,那麼泛型則爲咱們提供了算法的重用。下面咱們將實現一個泛型版本的冒泡排序。
public static int FourthVersionBubbleSort<T>(List<T> list) where T:IComparable<T> { int count = list.Count - 1, index = 0; bool change; int number = 0; do { change = false; for (int i = 0; i < count; i++) { if (list[i].CompareTo(list[i + 1]) > 0) { T temp = list[i]; list[i] = list[i + 1]; list[i + 1] = temp; change = true; index = i; // 記錄最後一次交換的位置 } number++; } count = index; } while (change); return number; }
執行 Main():
List<string> stringList = new List<string> { "Banana", "Apple", "Orange" }; Console.WriteLine("總共比較的次數:{0}", FourthVersionBubbleSort(stringList)); foreach (var item in stringList) { Console.Write(item.ToString().PadRight(10)); }
總共比較的次數:2
Apple Banana Orange
冒泡排序最優時間複雜度爲(即全部元素有序,只需遍歷一次便可) O(n),最差時間複雜度爲 O(n^2), 即當全部元素爲逆序時。