排序算法(五):快速排序及其优化分析

1.快速排序算法

快速排序算法:基于分治策略,通过 分类 + 递归 的方式对数组进行快速排序 ,一般选择每一部分的第一个元素作为基准元素。快速排序之所以快速,是因为相对于冒泡排序中对相邻元素进行比较,快速排序是设置基准值,通过跳跃式的交换将小于基准值和大于基准值的元素分成两部分,然后递归的重复该过程,直到排序结束。

注:快速排序的算法有很多,我一直不求甚解。最后发现 挖坑 + 递归 的方式是比较好理解的。

快速排序过程:

1)将基准值存入临时变量,此时基准值位置变为坑位
2)从左往右比较,将小于基准值的数值存入基准值位置,则挖坑位置变为本次索引结束位置,维护i变量
3)从右往左比较,将大于基准值的数值存入最新的坑位,则挖坑位置变为本次所以结束位置,维护j变量
4)当i>j时,一轮比较结束,将临时变量中的基准值存入最后的坑位。
5)递归的在新生成的数组中进行排序,直至数组排序完成。

挖坑 + 递归 的快排过程图解:

  • 将 5 设为基准值存入临时变量flag中,排序区间两端索引为  left = 0 ,right = 6
0123456
5436827
  • 从左往右遍历,将小于基准值的数值存入基准值位置,则挖坑位置变为本次索引结束位置,维护索引变量 i
0123456
4坑位36827
  • 从右往左遍历,将大于基准值的数值存入最新的坑位,则挖坑位置变为本次所以结束位置,维护索引变量 j
0123456
42368坑位7
  • 一轮结束后,将临时变量中的基准值存入最后的坑位。
0123456
423坑位867
  • 递归的对新生成的两部分数组进行相同逻辑的快速排序,直至排序完成。
public class QuickSort02 {
	public static void main(String[] args) {
		int[] arr = {2,5,6,3,8,4,9,1};
		quickSort(arr,0,7);
		for (int i : arr) {
			System.out.print(i + ",");
		}
	}
	
	/**
	 * 快速排序:一般将数组最左侧元素作为基准值
	 * @param arr 待排序数组
	 * @param left 数组左端点
	 * @param right 数组右端点
	 */
	public static void quickSort(int[] arr,int left,int right) {
		//判断递归到底的情况
		if(left < right) {
			//将基准值存入临时变量
			int flag = arr[left];
			//将数组的边界值存入变量 i 和 j 中,循环比较的同时注意维护。
			int i = left;
			int j = right;
			
			while(i<j) {
				//从右往左比较,将小于基准值的元素,放入坑位
				while(i<j && arr[j]>flag) {
					j--;
				}
				arr[i] = arr[j];    //将索引j中的元素放入索引i中,同时坑位变为索引j
				
				//从右往左比较,将大于基准值的元素,放入最新的坑位
				while(i<j && arr[i]<flag) {
					i++;
				}
				arr[j] = arr[i];   //将索引i中的元素放入索引j中,同时坑位变为索引i
			}
			arr[i] = flag;  //将基准值插入最后的坑位
			
			quickSort(arr,left,i-1);
			quickSort(arr,i+1,right);
		}
	}
}

2.算法优化分析

1)对于高级排序算法,在递归算法将要结束时,可以使用插入排序代替快速排序;

原因是:插入排序需要将元素不断插入到有序数组中,因此对于近乎有序的数组,插入排序能发挥很好的性能。

2)快速排序的最差情况是时间复杂度退化为O(N^2)。这是因为快速排序与归并排序虽然都是对数组进行递归的二分,但是快排每次都不是平均的二分,因此最后分层会大于logN。而对于近乎有序的数组,由于上面的方法固定的选取第一个元素作为分隔点,因此形成了近乎 N 层的选择操作,即退化成了O(N^2);

改进方案:随机的选取数组的分割点

3)对于重复值较多的数组,原先的快速排序没有考虑元素等于基准值的情况,因此重复值无论扔在那一侧,都会生成极不平均的分配,退化成O(N^2)。

改进方案:使用二路排序算法的同时,考虑元素等于基准值的情况

3.时间复杂度分析

快速排序是不稳定的算法。

快速排序的时间复杂度在最坏的情况下是O(N^2),平均的时间复杂度为O(N*logN)。因为被排序的数列中有N个数。遍历一次的时间复杂度为O(N),最少会遍历lg(N+1)次,最多N次。

注:快速排序是基于分治法的,如果将快速排序看做一颗二叉树。那么它的深度最少是 lg(N+1)。如果每层的分支都有一个仅包含一个元素,那么二叉树的深度最多是 N 。

4.空间复杂度分析

就原地排序而言,使用的空间复杂度是O(1)级别的;而快速排序中使用了递归算法,在每次递归的时候都要保持一些数据:

     最优的情况下空间复杂度为:O(logn)  ;每一次都平分数组的情况,类似于归并排序

     最差的情况下空间复杂度为:O( n )     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值