算法与数据结构之快速排序

经典快排:

给定一组数据,以这组数据的最后一个数为划分,假如最后一个数为x,则<=x放在左边,>x的放在右边
分别以左边和右边的最后一个数为划分,重复上述过程,这就是经典快排

荷兰国旗改进后的快排:

荷兰国旗问题:算法与数据结构笔试面试:荷兰国旗问题
还是以这组数据的最后一个数为划分,但是<x的放左边,==x的放中间,>x的放右边,再次从<x和>x的区域选最后一个数
重复上述过程

改进后的快排和经典快排的比较:

改进后的快排比较快,经典快排是每次只搞定一个数,也就是说,每次只能搞定x这一个数,比如说这组数据为:5,4,6,7,4,8,4,3,2,1,4
先是以4位区分,数据变为:3,2,1,4,4,4,4,5,6,7,8
只是搞定了下标为6位置的4,其他的4没有搞定,下次<=4的区域是以下标为5位置上的4作为划分,
但是改进后的快排第二次的划分是以下标为2位置的1作为划分,一下就把整个等于4的区域划分出来,不参与下次的比较,也就是说
当一组数据中有多个x时,经典快排只是搞定一个x,但是改进后的快排一次搞定所有x
两者时间复杂度差不多,但是在常数项上有一定差别。

经典快排存在的问题:

经典快排和数据状况有关,因为经典快排每次都是以最后一个位置的数作为划分,这样有可能导致划分的大于区域和
小于区域的数据规模不一致,如果每次小于区域和大于区域都有相同的规模,则时间复杂度可以做到O(n*logn),但是如果规模不一致
最坏情况,比如数据为:6,5,4,3,2,1 这就会导致只有大于区域没有小于区域,数据规模发生严重的偏差,时间复杂度可以做到O(N^2)

随机快排:

随机快排与经典快排唯一的不同,在选取划分的数据上不同,随机快排先在这组数据上随机选取一个数,然后将这个数和这组数据的最后
一个数交换,然后以最后这个数作为划分,这样的划分,不容易找出最坏情况,也不能确定划分的左边和右边规模的差异,此时,
随机快排的时间复杂度就变为一个概率事件,因为划分值的确定是等概率的,数组每一个位置的数据都有可能成为划分值,经过多次划分值
概率的累加,得到长期期望为O(nlogn),所以说随机快排的复杂度是一个长期期望的复杂度为O(nlogn),随机快排的额外空间复杂度为
O(logn),额外空间主要用在断点的位置,断点就是用来记录小于区域和大于区域的边界,因为先进行的是对小于x的数据放右边,
进行完小于区域的排放在进行大于放左边,那么进行完小于区域后,如何知道从什么位置开始进行大于区域呢,这就是设置断点,
存储边界位置,断点最好的情况下是每次递归都设在中间,这样额外空间复杂度为O(logn),最差情况下,比如数据为:6,5,4,3,2,1
第一次打在1,第二次打在2,如此下去,这样额外空间复杂度为O(n),因为划分值是随机的,所以额外空间复杂度也是一个概率,它的长期期望值为O(logn)
一个样本状况想要绕开它原始的数据状况,有两种方式,第一种用随机数打破它的随机状况,第二种哈希表

代码实现

public class QuickSort {
	public static void quickSort(int[] arr) {
		if(arr == null || arr.length < 2){
			return;
		}
		
		quickSort(arr, 0, arr.length - 1);
	}
	
	public static void quickSort(int[] arr, int L, int R){
		if (L < R) {
			swap(arr, L + (int)(Math.random() * (R - L + 1)), R); //将这行代码注释掉,就是经典快排
			int res[] = partition(arr, L, R);
			quickSort(arr, L, res[0]);
			quickSort(arr, res[1], R);
		}
	}
	
	public static int[] partition(int[] arr, int L, int R){
		int less = L - 1;
		int more = R;
		while(L < more){
			if(arr[L] < arr[R]){
				swap(arr, ++less, L++);
			}else if (arr[L] > arr[R]) {
				swap(arr, L, --more);
			}else {
				L++;
			}
		}
		
		swap(arr, more++, R);
		
		return new int[]{less, more};
	}
	
	public static void swap(int[] arr, int i, int j){
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值