快速排序
快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:速排序和归并排序类似,也是运用了递归的思想,通过一趟排序将要排序的数据分割成独立的两部分,每次选取一个主元(Pivot),使得主元左边的的元素都比主元小,主元右边的元素都大于主元,然后分别对主元两边再递归的调用QuickSort。
步骤
step1:选取主元,然后通过左右两边元素的交换使得使得主元左边的的元素都比主元小,主元右边的元素都大于主元。
step2:递归的再主元左右两边执行step1,直到区间长度为1.
选取主元
// 主流的选择主元方法 //取 最左边 最右边 最中间 三个数的 中位数
int Media3(ElemType *A,int Left,int Right){ //选主元
int Center = (Left + Right) / 2;
if(A[Left] > A[Center])
swap(A[Left],A[Center]);
if(A[Left] > A[Right])
swap(A[Left],A[Right]);
if(A[Center] > A[Right])
swap(A[Center] , A[Right]);
//得到 A [Left] <= A[Center] <= A[Right];
swap(A[Center],A[Right-1]); // 将Pivot 藏到右边 ;
return A[Right-1];
}
主流的选取主元的方法为:选取 当前区间最左边 最右边 以及最终间三个数的中位数。
我们通过swap使得 左中右有序,然后将中间的元素与 Right-1位置元素互换位置,这样需要变动位置的仅仅是Left+1 到Right-2了;
划分集合
使得左边元素都小于主元, 右边元素都大于主元
int i = Left, j =Right - 1;
for(;;){ //集合划分
while( A[++i] < Pivot){} //找到左边比Pivot大的数停止
while(A[--j] > Pivot){}//找到右边比Pivot小的数停止
if( i < j)
swap(A[i],A[j]);
else break; //如果 i在 j的右边,说明集合划分完毕
}
swap(A[i],A[Right-1]); /最后将主元放到应在的位置
当然,因为使用了递归,所以在小规模数据的情况下,快速排序的效率可能还不如简单排序,因此我们需要判断下当前的规模。通过设置CutOff变量,如果当前递归执行的区间长度大于这个值我们继续QuickSort,否则执行InsertionSort。
源代码
void Insertion_Sort(ElemType *A,int n){
for(int i = 1;i<n;i++){
ElemType tmp = A[i];
int j;
for( j=i; j > 0 && A[j-1] > tmp ;j--)
A[j] = A[j-1]; //遇到逆序就交换
A[j] = tmp;
}
}
int CutOff = 10;
// 主流的选择主元方法 //取 最左边 最右边 最中间 三个数的 中位数
int Media3(ElemType *A,int Left,int Right){ //选主元
int Center = (Left + Right) / 2;
if(A[Left] > A[Center])
swap(A[Left],A[Center]);
if(A[Left] > A[Right])
swap(A[Left],A[Right]);
if(A[Center] > A[Right])
swap(A[Center] , A[Right]);
//得到 A [Left] <= A[Center] <= A[Right];
swap(A[Center],A[Right-1]); // 将Pivot 藏到右边 ;
return A[Right-1];
}
void QuickSort(ElemType *A,int Left,int Right){ //递归程序 , 需要知道左右两端
if(CutOff<=Right - Left){
int Pivot = Media3(A ,Left,Right);
int i = Left, j =Right - 1;
for(;;){ //集合划分
while( A[++i] < Pivot){} //找到左边比Pivot大的数停止
while(A[--j] > Pivot){}//找到右边比Pivot小的数停止
if( i < j)
swap(A[i],A[j]);
else break; //如果 i在 j的右边,说明集合划分完毕
}
swap(A[i],A[Right-1]); //将 原来藏在Right -1 位置的主元交换到应该的位置,此时的位置是确定的
QuickSort(A,Left,i-1); //递归的处理左边
QuickSort(A,i+1,Right); //递归的处理右边
}
else //因为QuickSort处理小规模数据较慢(递归),因为在小于CutOff时调用InsertionSort
Insertion_Sort(A+Left,Right-Left+1);
}
void Quick_Sort(ElemType *A,int n){ //快排接口
QuickSort(A,0,n-1);
}