快速排序
取一个数,利用双指针,找到该数的位置,再递归处理该数左边的数组和右边的数组;
算法的速度关键在于每次找的的数最好都为数组中的中位数;
方法1:
每次都取头部元素,找到其位置;
#include<iostream>
using namespace std;
#define MAXN 100010
int N;
int T[MAXN];
void input()
{
cin>>N;
for(int i=0;i<N;i++)
cin>>T[i];
}
void Swap(int &a,int &b)
{
int temp=a;
a=b;
b=temp;
}
void QuickSort(int A[],int L,int R)
{
if(R<=L) return;
int temp=A[L];
int head=L;
int tail=R+1;
while(1){
while(A[++head]<temp) ;
while(A[--tail]>temp) ;
if(head<tail) Swap(A[head],A[tail]);
else break;
}
Swap(A[tail],A[L]);
//tail最终在小于A[l]的位置,head最终在大于A[L]的位置
//完成对L位置的放置
//把A[L]和tail交换,可以把小于A的放到左边
QuickSort(A,L,tail-1);
QuickSort(A,tail+1,R);
return;
}
void output()
{
cout<<T[0];
for(int i=1;i<N;i++)
cout<<" "<<T[i];
}
int main()
{
input();
QuickSort(T,0,N-1);
output();
}
注意点
while(A[++head]<temp) ;
while(A[--tail]>temp) ;
这种写法可以有效提高运行速度,所以head的初始化往左移了一个元素,tail的初始化也右移了一个元素;
int head=L;
int tail=R+1;
运行测试结果 4413 ms
因为每次都取头部元素,若为有序数组或逆序数组则会很慢;
方法2:
中位数
每次取操作数组中头中尾三个数的中位数,找到这个数的正确位置;
#include<iostream>
using namespace std;
#define MAXN 100010
int N;
int T[MAXN];
void input()
{
cin>>N;
for(int i=0;i<N;i++)
cin>>T[i];
}
void Swap(int &a,int &b)
{
int temp=a;
a=b;
b=temp;
}
void step1(int A[],int L,int R)
{
int Mid = (L+R)/2;
if(A[L]>A[Mid]) Swap(A[L],A[Mid]);
if(A[L]>A[R]) Swap(A[L],A[R]);
if(A[Mid]>A[R]) Swap(A[Mid],A[R]);
Swap(A[Mid],A[R-1]);
}
// 取三个数找到中位数,放入倒数第二个位置;
//对A[L+1]~A[R-2]进行查找,找到适合A[R-1]的位置;
void QuickSort(int A[],int L,int R)
{
if(R<=L) return;
step1(A,L,R);
int temp=A[R-1];
int head=L-1;
int tail=R-1;
while(1){
while(A[++head]<temp); //这里写法不同
while(A[--tail]>temp); //这里速度差异很大
if(head<tail) Swap(A[head],A[tail]);
else break;
//当要退出循环时,head此时以及大于tail,再做一次增加就会让后续的swap出错
}
Swap(A[R-1],A[head]);
//tail最终在小于A[l]的位置,head最终在大于A[L]的位置
//完成对L位置的放置 //把A[L]和head交换,可以把大于他的放到右边
QuickSort(A,L,head-1);
QuickSort(A,head+1,R);
return;
}
void output()
{
cout<<T[0];
for(int i=1;i<N;i++)
cout<<" "<<T[i];
}
int main()
{
input();
QuickSort(T,0,N-1);
output();
}
step1操作把数组中三个数位置正确放置,再把中位数放到R-1的位置上;
int head=L-1;
int tail=R-1;
同样,head和tail的设置都为要遍历的数字左右各偏一个,方便后面操作;
运行测试结果 75 ms
代码2:
/* 快速排序 */
#include<iostream>
using namespace std;
#define MAXN 100010
int N;
int T[MAXN];
void input()
{
cin>>N;
for(int i=0;i<N;i++)
cin>>T[i];
}
void Swap(int *a,int *b)
{
int temp=*a;
*a=*b;
*b=temp;
}
int Median3( int 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藏到右边*/
/* 只需要考虑A[Left+1] … A[Right-2] */
return A[Right-1]; /* 返回基准Pivot */
}
void Qsort( int A[], int Left, int Right )
{ /* 核心递归函数 */
int Pivot, Cutoff, Low, High;
if(Left>=Right) return;
//if ( Cutoff <= Right-Left ) { /* 如果序列元素充分多,进入快排 */
Pivot = Median3( A, Left, Right ); /* 选基准 */
Low = Left-1; High = Right-1;
while (1) { /*将序列中比基准小的移到基准左边,大的移到右边*/
while ( A[++Low] < Pivot ) ;
while ( A[--High] > Pivot ) ;
if ( Low < High ) Swap( &A[Low], &A[High] );
else break;
}
Swap( &A[Low], &A[Right-1] ); /* 将基准换到正确的位置 */
Qsort( A, Left, Low-1 ); /* 递归解决左边 */
Qsort( A, Low+1, Right ); /* 递归解决右边 */
//}
// else InsertionSort( A+Left, Right-Left+1 ); /* 元素太少,用简单排序 */
}
void QuickSort( int A[], int N )
{ /* 统一接口 */
Qsort( A, 0, N-1 );
}
void output()
{
cout<<T[0];
for(int i=1;i<N;i++)
cout<<" "<<T[i];
}
int main()
{
input();
QuickSort(T,N);
output();
}
//
//答案正确
//25 09-排序1 C++ (g++) 94 ms