16. 排序--簡單排序

排序

方法模板

void X_Sort(ElementType[] A, int N)
  • 大多數情況下,爲簡單起見,討論從小到大的整數排序
  • N是正整數,表示數組的長度

前提

  • 只討論基於比較的排序(例如通過 > = < 進行比較)
  • 只討論內部排序(所有數據加載入內存中)
  • 穩定性:任意兩個相等的數據,排序前後的相對位置不發生改變
  • 沒有一種排序是任何情況下都表現最好的

簡單排序

冒泡排序

算法原理

從後往前開始遍歷:

  1. 比較相鄰的兩個元素,如果第二個元素比第一個元素小,則進行交換
  2. 從開始一對到最後一對,對每一對相鄰元素做2的工作。這步操作完成後,最後的元素應該是最大的元素
  3. 重複以上步驟,直到倒數第一個元素(最後一個元素不參與上述循環)
  4. 持續每次對越來越少的元素重複以上的步驟,直到沒有任何一對元素需要比較

實現

void Bubble_Sort(ElementType[] A, int N) {
    for (P = N - 1; P >= 0; P--) {
        flag = 0;           // 用於標識這趟冒泡過程是否進行了元素的交換
        for (i = 0; i < P; i++) {   // 一趟冒泡過程
            if (A[i] > A[i + 1])  {
                Swap(A[i], A[i + 1]);
                flag = 1;   // 標識元素進行了交換
            }
        }

        if (flag == 0)  // 全程無交換,說明數組已經有序了,不需要再進行排序了
            break;
    }
}
  • 時間複雜度:
    • 最好情況:已經順序排好,T=O(N)
    • 最壞情況:逆序排好,T=O(N2)
  • 穩定性:基於A[i] > A[i + 1]的判斷方式,該冒泡排序是穩定
  • 冒泡排序可以處理單向鏈表的排序

插入排序

算法原理

從第二個元素遍歷到最後一個元素:
1. 記錄當前元素爲temp
2. 從當前位置向前遍歷,如果前一個元素大於temp,則把下個元素後移,直到前一個個元素小於或等於temp
3. 把temp置於空出來的位置

實現

void Insertion_Sort(ElementType[] A, int N) {
    for (P = 1; P < N; P++) {
        temp = A[P];    // 記錄要比較的元素
        for (i = P; i > 0 && A[i - 1] > temp; i--)
            A[i] = A[i - 1];    // 向後移動元素,空出空位

        A[i] = temp;    // 元素置於空位
    }
}
  • 時間複雜度:
    • 最好情況:已經順序排好,T=O(N)
    • 最壞情況:逆序排好,T=O(N2)
  • 穩定性:基於A[i - 1] > temp的判斷方式,該插入排序是穩定

時間複雜度下界

逆序對

對於下標i<j ,如果A[i] > A[j],則稱<i,j> 是一對逆序對(inversion)

  • 定理:任意N 個不同元素組成的序列平均具有N(N1)/4 個逆序對

逆序對與排序

對於冒泡、插入排序:

  • 交換2個相鄰元素正好消去1個逆序對
  • n 個逆序對,則需要交換n 次元素
  • 插入排序:T(N,I)=O(N+I)N 是元素的個數,I 是逆序對的個數
    • 如果序列基本有序,則插入排序簡單且高效

對於排序:

  • 定理:任何僅以交換相鄰兩元素來排序的算法,其平均時間複雜度爲Ω(N2)
  • 如果要提高算法效率,必須
    • 每次消去不止1個逆序對
    • 每次交換相隔較遠的2個元素
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章