快速排序 09-排序1 排序 (25分)

快速排序

取一个数,利用双指针,找到该数的位置,再递归处理该数左边的数组和右边的数组;
算法的速度关键在于每次找的的数最好都为数组中的中位数;

方法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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值