快速排序的实现(整理)

快速排序的基本思路是,在给定数组中选定一个数 v v v 并将数组中元素重新排列使得 v v v 左边的元素小于等于它右边的元素大于等于它,然后继续对左右两边的子序列进行排序。

对数组 S S S

  1. S S S中元素个数为0 or 1 ,return
  2. ∀ v ∈ S \forall v\in S vS
  3. S S S中余下元素分为两个不相交集合:
    S 1 = { x ∈ S − { v } ∣ x ≤ v } S_1=\{x\in S-\{v\} |x\leq v\} S1={xS{v}xv} S 2 = { x ∈ S − { v } ∣ x ≥ v } S_2=\{x\in S-\{v\} |x\ge v\} S2={xS{v}xv}
  4. 分别对 S 1 S_1 S1 S 2 S_2 S2进行快排

由此可看出优化的关键在于 2取点 和 3分割 这两步的实现

取点

取第一个元素

输入是预排序或反序时会产生很糟糕的分割

取随机元素(randomized quicksort)

随机数的生成有一定的开销

取数组左端、右端、中间位置上三个数的中位数(median-of-three method)

能够避免预排序输入时产生坏情况

分割

常规做法

(数据结构书上就用的这个

  1. (若 v v v 不是第一个元素) 将 v v v 与第一个元素交换
  2. i , j i,j i,j 分别从待分割数据段左右向中间移动,具体看代码吧,代码比文字描述更直观
while(i<j) {
	while(i<j && arr[j]>=v) --j;
    if(i<j) S[i++]=arr[j];
    while(i<j && arr[i]<= v) ++i;
    if(i<j) arr[j--]=arr[i];
}
  1. 递归

单侧递归

以左侧为例,分割后将左侧子序列递归,将 l l l 移至分割点右侧继续对右侧的分割

(以下代码现写的,没执行过,会意就行XD)

void qsort_2(int *arr, int l, int r){
	while(l<r){
		int i=l,j=r,v,m=(l+r)/2;	//取点采用三数中值分割
		v = arr[l]+arr[r]+arr[m]-max(arr[l],arr[r],arr[m])-min(arr[l],arr[r],arr[m]);
		if(arr[r]==v) {arr[r]=arr[l]; arr[l]=v;}
    	if(arr[m]==v) {arr[m]=arr[l]; arr[l]=v;}
    
    	while(i<j){
        	while(i<j && arr[j]>=v) --j;
    		if(i<j) S[i++]=arr[j];
    		while(i<j && arr[i]<= v) ++i;
    		if(i<j) arr[j--]=arr[i];
    	}
    	arr[i] = v;
    	qsort_2(arr,l,i-1);//左子序列进入递归 
        l = i+1;		   //l移到当前分割点右边,继续对右子序列进行分割
	} 
    return ;
}

不知道叫啥

同样是 i , j i,j i,j 分别从两端向中间移动, i , j i,j i,j 都停止时交换 i , j i,j i,j 所指位置的值

(算法书上一般核心思想就是这个,这里还结合了前文提到的单侧递归来实现

(同上会意就行

void qsort_3(int *arr, int l, int r){
    while(l<r){
		int i=l,j=r,v,m=(l+r)/2;	//取点采用三数中值分割
		v = arr[l]+arr[r]+arr[m]-max(arr[l],arr[r],arr[m])-min(arr[l],arr[r],arr[m]);
		if(arr[r]==v) swap(arr[r],arr[l]);
    	if(arr[m]==v) swap(arr[m],arr[l]);
    
    	do{
            while(arr[i]<v) ++i;
            while(arr[j]>v) --j;
            if(i<=j){
                swap(arr[i],arr[j]);
                ++x;
                --y;
            }
        }while(i<=j);
        
    	qsort_3(arr,l,j);//左子序列进入递归 
        l = v;		   //l移到当前分割点右边,继续对右子序列进行分割
	} 
    return ;
}

小数组优化

子数组足够小( N ≤ 15 N\leq15 N15)时改用插入排序

或不进行排序,在快排结束后进行一次插入排序

.
.
.

//做完这次整理的收获是,原来课本和我自己入的几本书之间水平是真的有差距的啊(课本太菜了(连课本都没读透的我更菜,对不起

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值