1. 常用經典排序算法
冒泡排序、插入排序、選擇排序;
O(n^2)
快速排序、歸併排序; O(nlogn)
計數排序、基數排序、桶排序; O(n)
2. 如何評價和分析一個排序算法的效率
- 排序算法的執行效率分析
(1). 最好情況、最壞情況、平均情況時間複雜度
對於不同有序度的數據,排序的執行時間不一樣.
在分析排序算法的時間複雜度時,分別給出最好情況、最壞情況、平均情況下的時間複雜度,並一一對應的最好、最壞時間複雜度的原始數據。
(2). 事件複雜度的係數、常數、低階
時間複雜度反應的是數據規模 n 很大的時候的一個增長趨勢。
但是當數據規模較小時, 對同一階時間複雜度的排序算法性能對比時, 需要把係數、常數、低階也考慮進來。
(3). 比較次數和交換(移動)次數
基於比較的排序算法涉及兩種操作: 元素大小比較,元素交換和移動
- 排序算法的內存消耗分析
算法的內存消耗可以通過空間複雜度來衡量。針對排序算法的空間複雜度,引入一個新的概念, 原地排序: 特指空間複雜度O(1)的排序算法
。
- 排序算法的穩定性分析
除了執行效率和內存消耗,還有一個重要度量指標 – 穩定性
。
穩定性: 即如果待排序的序列中存在值相等的元素,經過排序之後,相等元素之間原有的先後順序不變。
則稱其爲穩定的排序算法,反之則爲不穩定的排序算法。
3. 排序方法一: 冒泡排序
冒泡排序“只會”操作相鄰的兩個數據。
“只會”, 說明冒泡排序僅對相鄰的兩個元素進行比較。
// 冒泡排序,a表示數組,n表示數組大小
public void bubbleSort(int[] a, int n) {
if (n <= 1) return;
for (int i = 0; i < n; ++i) {
// 提前退出冒泡循環的標誌位
boolean flag = false;
for (int j = 0; j < n - i - 1; ++j) {
if (a[j] > a[j+1]) { // 交換
int tmp = a[j];
a[j] = a[j+1];
a[j+1] = tmp;
flag = true; // 表示有數據交換
}
}
if (!flag) break; // 沒有數據交換,提前退出
}
}
根據數據的有序度不同,可以獲取冒泡排序
具有不情況下的時間複雜度:
那麼平均時間複雜度如何計算?
前面講過,平均時間複雜度就是加權平均期望時間複雜度,分析的時候要結合概率論的知識,其中涉及到比較複雜的數學推理和計算。爲了避免複雜的討論,在這裏提出一種
有序度
和無序度
的概念來進行分析。
- 逆序度 = 滿有序度 - 有序度
1,2,3,4,5,6,有序度就是 n*(n-1)/2
,也就是 15。我們把這種完全有序的數組的有序度叫作滿有序度。
有序元素對:a[i] <= a[j], 如果i < j。
對冒泡分析實戰分析: 對於包含 n 個數據的數組進行冒泡排序,平均交換次數是多少呢?
最壞的情況下: 初始狀態無序,有序度爲0, 需要交換 n*(n-1)/2 次;
最好的情況下: 初始狀態有序,有序度爲 n*(n-1)/2 , 需要交換0次;
平均情況下: n*(n-1)/4次
==> 平均情況下的時間複雜度爲O(n^2)