介紹
排序演算法可以分為內部排序和外部排序,內部排序是資料記錄在記憶體中進行排序,而外部排序是因排序的資料很大,一次不能容納全部的排序記錄,在排序過程中需要訪問外存。常見的內部排序演算法有:插入排序、希爾排序、選擇排序、氣泡排序、歸併排序、快速排序、堆排序、基數排序等。用一張圖概括:
關於時間複雜度:
- 平方階 (O(n2)) 排序 各類簡單排序:直接插入、直接選擇和氣泡排序。
- 線性對數階 (O(nlog2n)) 排序 快速排序、堆排序和歸併排序。
- O(n1+§)) 排序,§ 是介於 0 和 1 之間的常數。 希爾排序。
- 線性階 (O(n)) 排序 基數排序,此外還有桶、箱排序。
關於穩定性:
穩定的排序演算法:氣泡排序、插入排序、歸併排序和基數排序。
不是穩定的排序演算法:選擇排序、快速排序、希爾排序、堆排序。
名詞解釋:
n:資料規模
k:“桶”的個數
In-place:佔用常數記憶體,不佔用額外記憶體
Out-place:佔用額外記憶體
穩定性:排序後 2 個相等鍵值的順序和排序之前它們的順序相同
氣泡排序演算法
氣泡排序(Bubble Sort)也是一種簡單直觀的排序演算法。它重複地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個演算法的名字由來是因為越小的元素會經由交換慢慢“浮”到數列的頂端。
作為最簡單的排序演算法之一,氣泡排序給我的感覺就像 Abandon 在單詞書裡出現的感覺一樣,每次都在第一頁第一位,所以最熟悉。氣泡排序還有一種優化演算法,就是立一個 flag,當在一趟序列遍歷中元素沒有發生交換,則證明該序列已經有序。但這種改進對於提升效能來說並沒有什麼太大作用。
-
動畫演示
-
思想原理
- 比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
- 對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。這步做完後,最後的元素會是最大的數。
- 針對所有的元素重複以上的步驟,除了最後一個。
- 持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較。
-
程式碼實現
public static void bubbleSort(int[] array){ //3 1 5 8 2 9 4 6 7 n*(n-1)/2 n for(int i=array.length-1;i>0;i--) { boolean flag=true; for (int j = 0; j < i; j++) { if (array[j] > array[j + 1]) { int temp = array[j]; array[j] = array[j + 1]; array[j + 1] = temp; flag=false; } } if(flag){ break; } } } 複製程式碼
-
使用場景
- 資料量足夠小,比如鬥牛遊戲的牌面排序
選擇排序演算法
-
簡介
選擇排序是一種簡單直觀的排序演算法,無論什麼資料進去都是 O(n²) 的時間複雜度。所以用到它的時候,資料規模越小越好。唯一的好處可能就是不佔用額外的記憶體空間了吧。
-
動畫演示
-
演算法步驟
- 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
- 再從剩餘未排序元素中繼續尋找最小(大)元素,然後放到已排序序列的末尾。
- 重複第二步,直到所有元素均排序完畢。
-
程式碼實現
/** *選擇排序 */ public void selectSort(int[] arr) { for (int j = 0; j < arr.length - 1; j++) { //定義一個最小值 int min = j; for (int i = j + 1; i < arr.length; i++) { if (arr[j] > arr[i]) { min = arr[i]; } } //如果第一位已經是最小值了就不用替換了 一定保證程式達到最優; if (min != j) { int temp = arr[min]; arr[min] = arr[j]; arr[j] = temp; } } } 複製程式碼
-
使用場景
快速排序的基礎
參考例子
利用蠻力法給牌進行排序(氣泡排序)
-
編寫 卡片 > 牌 資料 model
/** * 牌的資料 Bean * */ public class Cards implements Comparable{ public int pokerColors;//花色 public int cardPoints;//點數 public Cards(int pokerColors, int cardPoints) { this.pokerColors = pokerColors; this.cardPoints = cardPoints; } //提供一個方法,用來比較物件的大小 @Override public int compareTo(@NonNull Object o) { Cards c=(Cards)o; if(this.cardPoints>c.cardPoints){ return 1; }else if(this.cardPoints<c.cardPoints){ return -1; } if(this.pokerColors>c.pokerColors){ return 1; }else if(this.pokerColors<c.pokerColors){ return -1; } return 0; } @Override public String toString() { return "Cards{" + "pokerColors=" + pokerColors + ", cardPoints=" + cardPoints + '}'; } } 複製程式碼
-
卡片進行排序
public void testCards() { Cards [] cards = {new Cards(3,9),new Cards(1,10),new Cards(2,6)}; for (int i = cards.length - 1; i > 0; i--) { for (int j = 0; j < i; j++) { if (cards[j].compareTo(cards[j+ 1] ) > 0 ){ Cards temp =cards[j]; cards[j] = cards[j+1]; cards[j+1] = temp; } } } } 複製程式碼