16. 排序--簡單排序
阿新 • • 發佈:2019-01-07
排序
方法模板
void X_Sort(ElementType[] A, int N)
- 大多數情況下,為簡單起見,討論從小到大的整數排序
- N是正整數,表示陣列的長度
前提
- 只討論基於比較的排序(例如通過 > = < 進行比較)
- 只討論內部排序(所有資料載入入記憶體中)
- 穩定性:任意兩個相等的資料,排序前後的相對位置不發生改變
- 沒有一種排序是任何情況下都表現最好的
簡單排序
氣泡排序
演算法原理
從後往前開始遍歷:
- 比較相鄰的兩個元素,如果第二個元素比第一個元素小,則進行交換
- 從開始一對到最後一對,對每一對相鄰元素做2的工作。這步操作完成後,最後的元素應該是最大的元素
- 重複以上步驟,直到倒數第一個元素(最後一個元素不參與上述迴圈)
- 持續每次對越來越少的元素重複以上的步驟,直到沒有任何一對元素需要比較
實現
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(N−1)/4 個逆序對
逆序對與排序
對於冒泡、插入排序:
- 交換2個相鄰元素正好消去1個逆序對
- 有
n 個逆序對,則需要交換n 次元素 - 插入排序:
T(N,I)=O(N+I) ,N 是元素的個數,I 是逆序對的個數
- 如果序列基本有序,則插入排序簡單且高效
對於排序:
- 定理:任何僅以交換相鄰兩元素來排序的演算法,其平均時間複雜度為
Ω(N2) - 如果要提高演算法效率,必須
- 每次消去不止1個逆序對
- 每次交換相隔較遠的2個元素