算法代码如下:
/// <summary>
/// 快速排序的分隔,即:对于一个指定的主元x,找到位置i,使得i的左边元素都小于等于x,右边都大于等于x.
/// </summary>
/// <param name="A"></param>
/// <param name="p"></param>
/// <param name="q"></param>
/// <returns></returns>
private int QuickSortPartion(int[] A, int p, int q)
{
int theCount = q - p + 1;
//只有一个元素的情况,返回-1表示不用继续分割
if (theCount==1)
{
return -1;
}
//如果元素为2,则不用继续分割,只需要简单处理即可,这可以节省一些时间,但不是必须.
if (theCount == 2)
{
if (A[p] > A[q])
{
int tmp = A[p];
A[p] = A[q];
A[q] = tmp;
}
return -1;
}
//随机获取主元
Random theR=new Random(10);
int theMasterIndex = theR.Next(1, theCount);
int theMasterP = p + theMasterIndex -1;
//找到主元x,并与下界元素交换。
int theX = A[theMasterP];
A[theMasterP] = A[p];
A[p] = theX;
//寻找i,使得小于i位置的元素都小于等于thex,大于i位置的元素都大于thex.i初始位置为p.
int i = p;
//j初始位置为i+1;
for(int j=p+1;j<=q;j++)
{
//如果A[j]小于等于主元,则主元位置i右移一位,A[i]与A[j]交换
if (A[j] <= theX)
{
i++;
int theTmp = A[j];
A[j] = A[i];
A[i] = theTmp;
}
}
//做一次交换,将主元放到位置i.
A[p] = A[i];
A[i] = theX;
return i;
}
/// <summary>
/// 快速排序,主函数.
/// </summary>
/// <param name="A"></param>
/// <param name="S"></param>
/// <param name="E"></param>
private void QuickSort(int[] A, int S, int E)
{
//先找划分位置i
int theDivI = QuickSortPartion(A, S, E);
//不需要划分
if (theDivI < 0)
{
return;
}
int theP1_S = S, theP1_E = theDivI - 1;
int theP2_S = theDivI + 1, theP2_E = E;
//对左边递归快排
if (theP1_E >= S)
{
QuickSort(A, theP1_S, theP1_E);
}
//对右边递归快排.
if (theP2_S <= theP2_E)
{
QuickSort(A, theP2_S, theP2_E);
}
}
分治策略三步曲是:分,治,合。快排和归并排序同样采用的是分治策略,而且分治后的策略分支树都为2,但快排的优势在于,它不需要“合”,而归并排序的两个分支策略完成后,还有一个归并的过程。所以时间复杂度上归并显然不如快排。快排可以达到时间复杂度θ(n*lg(n)),归并的是θ(n*lg(n)).但快排的实际时间复杂度与其实现和输入都有关,最坏的情况,快排的时间复杂度也会达到θ(n^2),这个方面,归并排序的时间复杂度要均衡一些,与输入序列相关性不大。