快速排序
快速排序是一种在含n个数的输入数组上最坏情况运行时间为O(n2)的算法,平均性能的期望运行时间为O(nlgn),且O(nlgn)记号中隐含的常数因子很小。另外,它还能够进行原地置换排序。
快速排序是基于分治模式上的,分治过程三个步骤:
1.分解:把数组A[p...r]分成两个非空子数组A[p...q]和A[q+1...r],使得A[p...q]的每个元素都小于等于A[q+1...r]中的元素,下标q也在这个划分过程中进行计算。
2.解决:通过递归调用快速排序对子数组A[p...q]和A[q+1...r]排序。
3.合并:因为两个子数组是原地排序的,不需要将它们合并,整个数组A[p...r]已排序。
过程如下:
QuickSort(A,p,r)
{
if p<r
then q = Partition(A,p,r);
QuickSort(A,p,q);
QuickSort(A,q+1,r);
}
快速排序算法的关键是Partition过程,它对子数组A[p...r]进行划分,并得到划分的界限q:
Partition(A,p,r)
{
x = A[p];
i = p-1;
j = r+1;
while TRUE
do repeat j = j-1
until A[j] <= x
repeat i = i+1
until A[i] >= x
if i<j
then swap (A[i] , A [j])
else return j
}
代码如下:
void Swap(int &a, int &b)

...{
int t = a;
a = b;
b = t;
}
int Partition(int *A, int left, int right)

...{
int x = A[left];
int i = left - 1;
int j = right;

while(1)

...{
while(A[j]>x)
--j;
while(A[i]<x)
++i;
if(i<j)
Swap(A[i],A[j]);
else return j;
}
}
void QuickSort(int* A,int left, int right)

...{
if(left < right)

...{
int q = Partition(A,left,right);
QuickSort(A,left,q);
QuickSort(A,q+1,right);
}
}
void PrintArray(int data[], int n)

...{
int i;
for(i = 0; i < n; i++)

...{
printf("%d ", data[i]);
}
printf(" ");
}
void main()

...{

int A[] = ...{4, 1, 44, -12, 5, 125, 30};
QuickSort(A,0,6);
PrintArray(A,7);
}
当数组已经排序好(正序)时,快速排序的的时间代价是O(n2),而这对插入排序只要O(n)的时间
因为此时把数组划分为两部分,分别含1个和n-1个的数组,而快速排序的最佳情况是两个子数组大小都是n/2
改进(随机化版本):当数组还没有被划分时,可将元素A[p]与A[p...r]中随机选出的一个元素交换。
只要把Partition函数开头加入随机化即可:
Randomized_Partition(A,p,r)
{
i = Random(p,r)
swap (A[p],A[i])
return Partition(A,p,r)
}
相应地,在QuickSort里调用Randomized_Partition(A,p,r)
代码如下:
void Swap(int &a, int &b)

...{
int t = a;
a = b;
b = t;
}

int Partition(int *A, int left, int right)

...{
int x = A[left];
int i = left - 1;
int j = right;

while(1)

...{
while(A[j]>x)
--j;
while(A[i]<x)
++i;
if(i<j)
Swap(A[i],A[j]);
else return j;
}
}

int new_random(int min, int max)

...{
return (min + (int)(((float)rand()/RAND_MAX)*(max - min)));
}
int Randomized_Partition(int *A, int left, int right)

...{
int i = new_random(left, right);
Swap(A[i], A[right]);
return Partition(A, left, right);
}
void Randomized_QuickSort(int* A,int left, int right)

...{
if(left < right)

...{
int q = Randomized_Partition(A,left,right);
QuickSort(A,left,q);
QuickSort(A,q+1,right);
}
}
void PrintArray(int data[], int n)

...{
int i;
for(i = 0; i < n; i++)

...{
printf("%d ", data[i]);
}
printf(" ");
}
void main()

...{

int A[] = ...{4, 1, 44, -12, 5, 125, 30};
Randomized_QuickSort(A,0,6);
PrintArray(A,7);
}
另外,还有一个方案,是在待排序的数组里随机选三个元素,取值为第二大的那个作为基准数也可