本文讨论两种著名且颇有用的排序算法:插入排序,快速排序。算法
插入排序的思想与打牌起牌相似:每次从牌堆里拿一张牌,插入到已经排好序的牌中。数组
具体算法描述以下:bash
从第一个元素开始,该元素能够认为已经被排序less
取出下一个元素,从该元素开始,从后向前扫描表ide
若是前一个元素大于后一个元素,则交换两个元素的位置测试
重复步骤 3,直到前一个元素不大于后一个元素ui
重复步骤 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)。
分治法的基本思想是:将原问题分解为若干个规模更小但结构与原问题类似的子问题。递归地解这些子问题,而后将这些子问题的解组合为原问题的解。
步骤为:
从数列中挑出一个元素,称为"基准"(pivot),
从新排序数列,全部元素比基准值小的摆放在基准前面,全部元素比基准值大的摆在基准的后面(相同的数能够到任一边)。在这个分区结束以后,该基准就处于数列的中间位置。这个称为分区(partition)操做。
递归地(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) $$