快速排序(Quick Sort)
-
简介:
快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法。
快速排序的基本思想是通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
快速排序为非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此称为非线性时间比较类排序。
-
基本思想:
1、先从数列中取出一个数作为基准数。
2、分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3、再对左右区间重复第二步,直到各区间只有一个数。 -
示例:
public static void main(String[] args) { int[] array = new int[]{9, 5, 8, 4, 3, 7, 6, 1, 0, 2}; SystemUtils.print("->排序前:", array); quickSort(array, 0, 9); SystemUtils.print("->排序后:", array); } public static void quickSort(int[] arr, int left, int right) { //进行判断,如果左边索引比右边索引大,是不合法的,直接使用return结束这个方法 if(left>right) { return; } //定义变量保存基准数 int base=arr[left]; //定义变量i,指向最左边 int i=left; //定义变量j,指向最右边 int j=right; //当i和j不相遇的时候,在循环中进行检索 while(i!=j) { //向由j从右往左检索比基准数小的,如果检索到比基准数小的就停下 //如果检索到比基准数大的或者相等的,就继续检索 while(arr[j]>=base && i<j) { j--; //j从右边往左移动 } while(arr[i]<=base&&i<j) { i++; //i从左往右移动 } //代码走到这里,i停下了,j也停下了。然后交换i和j位置的元素 int temp=arr[i]; arr[i]=arr[j]; arr[j]=temp; } //如果上面while循环的条件不成立,会跳出这个循环,往下执行 //如果这个条件不成立说明i和j相遇了 //如果i和J相遇了,就交换基准数这个元素和相遇位置的元素 //把相遇位置的元素赋值给基准数这个位置的元素 arr[left]=arr[i]; //把基准数赋值给相遇位置的元素 arr[i]=base; //基准数在这里就归为了,左边的数字都比他小,右边的都比他大 //排基准数的左边 quickSort(arr, left, i-1); //排右边 quickSort(arr, j+1, right); }
输出结果:
->排序前:9,5,8,4,3,7,6,1,0,2 ->排序后:0,1,2,3,4,5,6,7,8,9
-
时间复杂度:
- 快速排序的一次划分算法从两头交替搜索,直到low和hight重合,因此其时间复杂度是O(n);而整个快速排序算法的时间复杂度与划分的趟数有关。
- 理想的情况是,每次划分所选择的中间数恰好将当前序列几乎等分,经过log2n趟划分,便可得到长度为1的子表。这样,整个算法的时间复杂度为O(nlog2n)。
- 最坏的情况是,每次所选的中间数是当前序列中的最大或最小元素,这使得每次划分所得的子表中一个为空表,另一子表的长度为原表的长度-1。这样,长度为n的数据表的快速排序需要经过n趟划分,使得整个排序算法的时间复杂度为O(n^2)。
-
稳定性:
快速排序需要一个基准值,在基准值的右侧找一个比基准值小的元素,在基准值的左侧找一个比基准值大的元素,然后交换这两个元素,此时会破坏稳定性,所以快速排序是一种不稳定的算法。