數據結構與算法第八節: 排序算法

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)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章