快排quick sort

目录

原理

例子

代码

快排部分

 递归部分

 测试代码

 测试结果


原理

快排的原理就是找一个数a,把要排序的数组分为三个部分,小于a的一部分数、等于a的一部分数、大于a的一部分数。我们在下文中用小于区、等于区、大于区来指代。

分好部分之后,不管其他数怎么样,a的位置一定跟最后排好序后的a的位置一样,因为最后排好序的数组也是可以分为小于a的部分、等于a的部分、大于a的部分,只不过小于区和大于区内部是有序的而已,等于区完全一致。

这就是快排的核心思想。我们为了降低时间复杂度,可以借鉴归并排序的思路,用递归的方法。每一次快排都将数组分为小于区、大于区、等于区,那么我们下一次快排就直接分别排序小于区和大于区即可。每次都把数组分成三份,排序其中两份,平均时间复杂度是O(NlogN)。

例子

假设有数组2 3 1 4 5 2,要用快排排序。先选择最后一个数:

然后从第一个数开始往后,跟最后一个数比较:

2等于2,不理它,继续往后:

 

3>2,将3和最后一个数前面的数交换,箭头仍停留在该位置

这时候,先不管最后那个2,将3作为大于区的成员:

再看当前箭头指向的5,仍然大于2,将5与大于区前面那个数交换,并把大于区的范围往前扩张:

4同理:

目前的大于区和等于区:

 

这时候1小于2了,把1和等于区的第一个数交换,作为新的小于区成员,并把箭头往前移动:

 

 这时候箭头指向了大于区当中,说明都已经排好序了,将最后的那个2放到等于区里,结束这一轮快排:

之后,我们再对左边的小于区和右边的大于区做快排,1可以不用排,以下是大于区的排序过程:

 之后再不断递归,最终整个数组都为有序数组:

代码

快排部分

int *partition(int *arr,int L,int R){//数组、左边界下标、右边界下标 
	int little_border=L-1;//小于区右边界 
	int big_boder=R;//大于区左边界 
	while(L<big_boder){//从头遍历到尾 
		if(arr[L]<arr[R]){//当前数比选定数小 
			swap(arr,++little_border,L++);//放在小于区里面,小于区范围++,进入下一个数 
		}
		else if(arr[L]>arr[R]){//当前数比选定数大 
			swap(arr,--big_boder,L);//放在大于区里面,大于区范围++,停在当前位置 
		}
		else{
			L++;//放着不动,相当于等于区,进入下一个数 
		}
	}
	swap(arr,big_boder,R);//最后把选定的数放在等于区 
	int *res=(int *)malloc(sizeof(int)*2);//最后返回一个数组
	res[0]=little_border+1;//数组成员有等于区的左边界 
	res[1]=big_boder;//还有等于区的右边界 
	return res;//函数返回这个数组的指针,方便我们进行下一次的递归快排 
}

 其中的swap函数就是最常用的交换函数,自己定义一个就行:

void swap(int *arr,int a,int b){
	int tmp=arr[a];
	arr[a]=arr[b];
	arr[b]=tmp;
}

 递归部分

void quick_sort(int *arr,int L,int R){//主函数中调用的函数,参数仍为数组、左边界下标、右边界下标
	if(L<R){
		swap(arr,L+rand()%(R-L+1),R);/*选择一个随机数作为最后一个数 
		这也是为什么平均时间复杂度能达到 O(logN)的原因 */
		int *p=partition(arr,L,R);//之前函数的返回值,也就是我们分割数组三部分的边界线 
		quick_sort(arr,L,p[0]-1);//对小于区进行快排 
		quick_sort(arr,p[0+1],R);//对大于区进行快排 
	}
}

 测试代码

#include"stdio.h"
#include"stdlib.h"
int *partition(int *arr,int L,int R);
void swap(int *arr,int a,int b){
	int tmp=arr[a];
	arr[a]=arr[b];
	arr[b]=tmp;
}

void quick_sort(int *arr,int L,int R){//主函数中调用的函数,参数仍为数组、左边界下标、右边界下标
	if(L<R){
		swap(arr,L+rand()%(R-L+1),R);/*选择一个随机数作为最后一个数 
		这也是为什么平均时间复杂度能达到 O(logN)的原因 */
		int *p=partition(arr,L,R);//之前函数的返回值,也就是我们分割数组三部分的边界线 
		quick_sort(arr,L,p[0]-1);//对小于区进行快排 
		quick_sort(arr,p[0+1],R);//对大于区进行快排 
	}
}

int *partition(int *arr,int L,int R){//数组、左边界下标、右边界下标 
	int little_border=L-1;//小于区右边界 
	int big_boder=R;//大于区左边界 
	while(L<big_boder){//从头遍历到尾 
		if(arr[L]<arr[R]){//当前数比选定数小 
			swap(arr,++little_border,L++);//放在小于区里面,小于区范围++,进入下一个数 
		}
		else if(arr[L]>arr[R]){//当前数比选定数大 
			swap(arr,--big_boder,L);//放在大于区里面,大于区范围++,停在当前位置 
		}
		else{
			L++;//放着不动,相当于等于区,进入下一个数 
		}
	}
	swap(arr,big_boder,R);//最后把选定的数放在等于区 
	int *res=(int *)malloc(sizeof(int)*2);//最后返回一个数组
	res[0]=little_border+1;//数组成员有等于区的左边界 
	res[1]=big_boder;//还有等于区的右边界 
	return res;//函数返回这个数组的指针,方便我们进行下一次的递归快排 
}

int main(){
	int arr[100]={0};
	int len=0;
	while(1){
		scanf("%d",&arr[len]);
		len++;
		if(getchar()=='\n'){
			break;
		}
	}
	quick_sort(arr,0,len-1);
	for(int i=0;i<len;i++){
		printf("%d ",arr[i]);
	}
}

 测试结果

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值