快速排序算法(Java版)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_41291067/article/details/102623419

1、快速排序概念:

快速排序时分治排序的一种排序算法,它将一个数组分成两个子数组,将两个部分独立的排序。快速排序和归并排序是互补的,归并排序将数组分成两个子数组分别排序,并将有序的子数组归并以将整个数组排序,而快速排序则是就当两个子数组都有序时,整个数组就自然有序了。归并中,递归调用发生在处理整个数组之前,而在快速中,递归调用发生在处理整个数组之后。

2、快速排序的过程:

在这里插入图片描述
1、先从序列中取出一个数作为基准数;
2、分区过程:将把这个数大的数全部放到它的右边,小于或者等于它的数全放到它的左边;
3、递归地对左右子序列进行,直到各区间只有一个数。

3、快速排序的时间复杂度:

最好情况

在最好的情况下,每次我们进行一次分区,我们会把一个序列刚好分为几近相等的两个子序列,这个情况也我们每次递归调用的是时候也就刚好处理一半大小的子序列。这看起来其实就是一个完全二叉树,树的深度为 O(logn),所以我们需要做 O(logn) 次嵌套调用。但是在同一层次结构的两个程序调用中,不会处理为原来数列的相同部分。因此,程序调用的每一层次结构总共全部需要 O(n) 的时间。所以这个算法在最好情况下的时间复杂度为 O(nlogn)。

事实上,我们并不需要如此精确的分区:即使我们每个基准值把元素分开为 99% 在一边和 1% 在另一边。调用的深度仍然限制在 100logn,所以全部运行时间依然是 O(nlogn)。

最坏情况

事实上,我们总不能保证上面的理想情况。试想一下,假设每次分区后都出现子序列的长度一个为 1 一个为 n-1,那真是糟糕透顶。这一定会导致我们的表达式变成:

T(n) = O(n) + T(1) + T(n-1) = O(n) + T(n-1)

这和插入排序和选择排序的关系式真是如出一辙,所以我们的最坏情况是 O(n²)。

4、代码实现:

import java.util.Arrays;

public class fastSort {
	public static void main(String[] args) {
		int[] array= {8,4,5,7,1,3,6,2};
		quickSort(array,0,array.length-1);
		System.out.println(Arrays.toString(array));
	}
	public static void quickSort(int[] arr,int left,int right) {
		int l = left;
		int r = right;
		int pivort = arr[(left+right)/2];
		int temp = 0;
		//while循环的目的是让比pivort小的放到它左边,比pivort大的值放到它的右边
		while(l<r) {
			//再pivort的左边找到一个比它大的值,才退出
			while(arr[l]<pivort) {
				l++;
			}
			while(arr[r]>pivort) {
				r--;
			}
			//pivort的左右两边的值已经按照左边全部时小于等于pivort和大于等于pivort,
			if(l>=r) {
				break;
			}
			//交换
			temp = arr[r];
			arr[r] = arr[l];
			arr[l] = temp;
			//如果交换完后发现arr[l]=pivort,r--
			if(arr[l]==pivort) {
				r--;
			}
			if(arr[r]==pivort) {
				l++;
			}
		}
		if(l==r) {
			l++;
			r--;
		}
		if(left<r) {
			quickSort(arr,left,r);
		}
		if(right>l) {
			quickSort(arr,l,right);
		}
	}
}

5、输出:

[1, 2, 3, 4, 5, 6, 7, 8]

参考来源

猜你喜欢

转载自blog.csdn.net/qq_41291067/article/details/102623419