《面试系列篇》——快速排序详解

目录

【一】前言

【二】快速排序概念

【三】代码详解

【四】总结


【一】前言

我们熟知常见的排序算法有:冒泡排序、选择排序、归并排序、插入排序、快速排序等;每种都有其不同的特点以及解法,并且每种排序都可以找到不同算法思路来解答,拿快速排序来讲,有递归和非递归的解法,以下就讲讲递归的快速排序的解法。

【二】快速排序概念

快速排序(Quick Sort)是对冒泡排序的一种改进。它的基本思想是:通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可以分别对着两部分记录继续进行排序,以达到整个序列有序。

过程解析:待排序的数组序列arr[],假设要从小到大以此从左至右给数组排序,取出其中一个arr[left]为基准元素,通常取第一个为基准元素poivt,先从数组的最右边arr[end-1]开始往左移动,直到找到第一个比基准元素小(arr[right]<poivt)的值,把它arr[right]放到arr[left]的位置;接下来再从左往右移动,直到找到比基准元素大的值arr[i],把它放到上述arr[right]的位置;当left指针与right指针指向同一个位置的时候,表明这趟(第一趟)排序已完成。

运用递归:运用递归的思想,其实也是分而治之的思想,来解决整个数组的排序。

从上图可以看到,完整的快速排序是建立在一趟快速排序之上的,它的具体步骤如下:

  1. 首先对待排序序列进行一趟快速排序(假设从左至右一次递增);
  2. 一趟排序下来之后,基准元素的左边都是比它小的元素,右边都是比它大的元素;
  3. 再对基准元素左边的序列进行快速排序,对右边也进行快速排序;
  4. 重复步骤2、3,直到序列排序完成。

从快速排序的步骤中我们不难发现:快速排序其实使用的是分而治之的思想,它的排序过程是一个递归调用的过程。

【三】代码详解

思路分析,核心的排序逻辑如下:

public static int partion(int[] arr,int left,int end){
	int povit = arr[left];//选取第一个为基准元素
	while(left < end){
		//从右向左开始移动,直到找到第一个比基准元素小的值
		while(left <end && arr[end] >= povit){
			end --;
		}
		arr[left] = arr[end];//将右边比基准元素小的值放在left的位置
		//从左向右开始移动,直到找到第一个比基准元素大的值
		while(left < end && arr[left] <= povit){
			left ++;
		}
		arr[end] = arr[left];//将左边比基准元素大的值放在end位置
	}
	//当第一趟排序完毕时,left和end指向同一个值,此时返回left位置,left=end且值是即基准元素
	arr[left] = povit;
	return left;
}

以数组:{10,5,7,12,1,9,13,8,6,3,11}为例要进行排序,从左至右一次递增。

1、选择10为基准元素povit,从右边开始向左边移动指针,找到第一个比10小的数为3,这时把3放到10的位置。

2、再从左边开始移动指针,也就是3的位置开始移动,找到比10大的值是12,把12放到之前(原来)3的位置处。

3、循环整个数组,当left指针和rigth指针指向同一个位置(left=right)时,这时第一趟排序完成,把基准元素的值赋值给当前指针位置,并返回。

第一趟完成排序后为:{3,5,7,6,1,9,8,10,13,12,11}

4、重复1和2两个步骤,以返回的值为基准元素点,递归调用上述3个步骤,最终完成

完整的代码程序,就是对一组数组进行递归的调用,如下:

public static int partion(int[] arr,int left,int end){
	int povit = arr[left];//选取第一个为基准元素
	while(left < end){
		//从右向左开始移动,直到找到第一个比基准元素小的值
		while(left <end && arr[end] >= povit){
			end --;
		}
		arr[left] = arr[end];//将右边比基准元素小的值放在left的位置
		//从左向右开始移动,直到找到第一个比基准元素大的值
		while(left < end && arr[left] <= povit){
			left ++;
		}
		arr[end] = arr[left];//将左边比基准元素大的值放在end位置
	}
	//当第一趟排序完毕时,left和end指向同一个值,此时返回left位置,left=end且值是即基准元素
	arr[left] = povit;
	return left;
}


public static void quickSort(int arr[],int left,int end){
	if(left < end){
		int pivot = partion(arr,left,end);
		
		//对左半部分递归
		quickSort(arr,left,pivot-1);
		
		//对右半部分递归
		quickSort(arr,pivot+1,end);
	}
}

最终得到结果:{1,3,5,6,7,8,9,10,11,12,13}

【四】总结

采用分而治之的递归思想是解决快速排序一个比较好的方案,递归的思想不止是用到排序里面,也可以用于查找里面,比如当需要在大数据量之中查找某个某个值时,也可以运用这种思想,从而达到提升查询效率。


面试连载系列篇

《面试系列篇》——11种常用的设计模式

《面试系列篇》——ShardingJdbc分库分表浅谈

《面试系列篇》——MySQL慢查询及解决方案

《面试系列篇》——面试官最喜欢问的Redis知识

《面试系列篇》——听说面试官喜欢问这些MySQL知识

《面试系列篇》——Paxos与Zookeeper分布式一致性面试必备

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序大视界

原创不易,请给点支持和鼓励吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值