引言
注:由于没有启用任何公示编辑器,为表示方便:以下涉及时间复杂度表示时,其渐近符号用以下符号代替:
本文将介绍三种能在O(nlgn)时间内排序n个数的算法:归并排序、堆排序和快速排序。它们都是基于比较的排序,前两种算法在最坏情况下达到此上界,快速排序在平均情况下达到此上界。
注:比较排序指排序结果中,各元素的次序基于输入元素间的比较。且可以证明:任何一个比较排序算法在最坏情况下,都需要做 $(nlogn)次的比较。故堆排序和归并排序都是渐近最优的比较排序算法。
一、归并排序
该算法是分治法的典型应用之一,为避免与分治法的文章重复叙述,本文侧重描述归并排序的基本思想以及具体的代码实现。
(1)基本思想:依照分治模式,该算法分为三步:
- 分解:将n个元素划分成两部分:每部分均为含有 n/2 个元素的子序列;
- 解决:用归并排序法对两个子序列递归地排序;
- 合并:合并两个已排序的子序列以得到排序结果。
注:在对子序列排序时,其长度为1时递归结束。因为单个元素被视为是已排好序的。
(2)算法描述:在上述步骤中,对于归并排序来说,【合并】部分最为关键。以下对其详细描述。
为做合并,引入一个辅助过程:Merge(A, p, q, r),其中A为输入数组,p、q和r是下标,满足p<=q<r.该步骤假设子数组 A[p...q] 和 A[q+1...r] 均已排好序。其中合并部分的伪代码如下:
(3)时间复杂度:假设归并排序长度为n的元素,所有的运行时间为:T(n).
【分解】步中只需计算出子数组的中间位置,常量时间:@(1);【解决】步中递归地求解两个规模为n/2的子问题,时间为:2T(n/2);【合并】步中最坏情况是两个部分中的元素分别都要比较一次,即用时@(n)。故关于归并排序的最坏情况运行时间T(n)的递归方程可表示为:
由主定理可以得之:T(n) = @(nlgn),此处lgn代表log2^n.
(4)算法实现
#include <stdio.h>
const int N = 6;
const int INF = 0x7fffffff; //infinite value
int input[N+1] = {-1, 2, 3, 3, 5, 7, 1};
int tempL[(N+1)/2+2];
int tempR[(N+1)/2+2];
void merge(int input[], int p, int q, int r)
{
int n1 = q-p+1;
int n2 = r-q;
int i, j;
for(i = 1; i <=n1; i++)