兩種經常使用的排序算法

本文討論兩種著名且頗有用的排序算法:插入排序,快速排序。算法

插入排序

插入排序的思想與打牌起牌相似:每次從牌堆裏拿一張牌,插入到已經排好序的牌中。數組

具體算法描述以下:bash

  1. 從第一個元素開始,該元素能夠認爲已經被排序less

  2. 取出下一個元素,從該元素開始,從後向前掃描表ide

  3. 若是前一個元素大於後一個元素,則交換兩個元素的位置測試

  4. 重複步驟 3,直到前一個元素不大於後一個元素ui

  5. 重複步驟 2~4spa

現有一組數組 A = [5, 6, 3, 1, 8, 7, 2, 4],共有八個記錄,排序過程以下:code

[5]   6   3   1   8   7   2   4
  ↑   │
  └───┘

[5, 6]   3   1   8   7   2   4
↑        │
└────────┘

[3, 5, 6]  1   8   7   2   4
↑          │
└──────────┘

[1, 3, 5, 6]  8   7   2   4
           ↑  │
           └──┘

[1, 3, 5, 6, 8]  7   2   4
            ↑    │
            └────┘

[1, 3, 5, 6, 7, 8]  2   4
   ↑                │
   └────────────────┘

[1, 2, 3, 5, 6, 7, 8]  4
         ↑             │
         └─────────────┘
 
[1, 2, 3, 4, 5, 6, 7, 8]

動態過程以下:
插入排序htm

代碼實現:

function isort(A, n, i, j, t) {
    for (i = 2; i <= n; i++) {
        # scan
        for (j = i; j > 1 && A[j-1] > A[j]; j--) {
            # swap 2 elements
            t = A[j-1]
            A[j-1] = A[j]
            A[j] = t
        }
    }
}


# 測試代碼
# 每一個數字佔一行
{ A[NR] = $0 }
END {
    isort(A, NR)
    for (i = 1; i <= NR; i++) {
        print A[i]
    }
}
要排序的文件:
$ cat isort.txt
5
6
3
1
8
7
2
4

排序後輸出:
$ awk -f isort.awk isort.txt
1
2
3
4
5
6
7
8

輸入倒序的10個數字:
$ seq 1 10 | tac | awk -f isort.awk
1
2
3
4
5
6
7
8
9
10

算法複雜度分析:
由於有兩層循環,因此算法複雜度爲
$$ O(n^2)$$

快速排序

快速排序是圖靈獎得主 C. R. A. Hoare 於1960 年提出的一種劃分交換排序。它採用了一種分治的策略,一般稱其爲分治法(Divide and Conquer)。
分治法的基本思想是:將原問題分解爲若干個規模更小但結構與原問題類似的子問題。遞歸地解這些子問題,而後將這些子問題的解組合爲原問題的解。

步驟爲:

  1. 從數列中挑出一個元素,稱爲"基準"(pivot),

  2. 從新排序數列,全部元素比基準值小的擺放在基準前面,全部元素比基準值大的擺在基準的後面(相同的數能夠到任一邊)。在這個分區結束以後,該基準就處於數列的中間位置。這個稱爲分區(partition)操做。

  3. 遞歸地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序。

圖解能夠看這裏,講得比較詳細。

代碼實現:

function swap(A, left, right, t) {
    t = A[left]
    A[left] = A[right]
    A[right] = t
}

function qsort(A, left, right, pivot, i, j) {
    if (left < right) {
        # select a pivot element
        pivot = left
        i = left
        j = right
        while (i < j) {
            # increment i till you get a number greater than the pivot element
            while (A[i] <= A[pivot] && i <= right)
                i++
            # decrement j till you get a number less than the pivot element
            while (A[j] > A[pivot] && j >= left)
               j--
            # if i < j swap the elements in locations i and j
            if (i < j) {
               swap(A, i, j)
            }
        }

        # when i >= j it means the j-th position is the correct position
        # of the pivot element, hence swap the pivot element with the
        # element in the j-th position
        swap(A, pivot, j)
        # Repeat quicksort for the two sub-arrays, one to the left of j
        # and one to the right of j
        qsort(A, left, j - 1)
        qsort(A, j + 1, right)
    }
}

# 測試代碼
{ A[NR] = $0 }
END {
    qsort(A, 1, NR)
    for (i = 1; i <= NR; i++) {
        print A[i]
    }
}

和插入排序同樣,測試以下:

$ cat isort.txt
5
6
3
1
8
7
2
4

$ awk -f qsort.awk isort.txt
1
2
3
4
5
6
7
8

$ seq 1 10 | tac | awk -f qsort.awk
1
2
3
4
5
6
7
8
9
10

算法複雜度分析:平均複雜度爲 $$ O(nlogn) $$

相關文章
相關標籤/搜索