学习《轻松学算法》之快速排序
快速排序是对冒泡排序的一种改进。
思想:
找到一个数key,把要排序的数据分成AB两部分,A部分的所有数据比key大,另一部分B所有数据比key都要小。例如(3,4,2,5,1,8,6),如果以key=3进行分类,那么就有(3,2,1)和(4,5,8,6)两部分。针对每一部分,我们进行相同的上述操作。如A部分(3,2,1),若key=3,操作以后是(2,1)和(3),再将(2,1)以key=2进行排序为(1)和(2),进行合并(1,2,3)。全部操作结束后,整个数据就会变得有序。这里其实用到了分治法,不停将问题分解成小问题。
原理:
1 我们要找到一个基准数,作为分成两部分的依据,一般选择每一个部分的第一个数字为基准数。
2 我们选择将数从大到小排列,那么我们就要将小于这个基准数的所有元素移动到基准数的右边,右边的数为A部分;将大于这个基准数的所有元素移动到基准数的左边,左边的数为B部分。
3 将A、B两个部分按照上述两步骤重新进行排序,直到每一个部分只有一个数字
4 合并所有部分的数字。
操作:
1 从数列array头部下标为i,尾部下标为j,基准数key为array的第一个数字
2 从数列的尾部往前开始与key进行比较,若尾部的数大于key,则两者对调,进行下一步,反之j - - ,这里的作用是找到第一个比基准数key大的数,并且与基准数key对调,使得大数往前移动。
3 key与大数对调以后,开始找小数。从数列的头部往后开始与key做比较,若头部的数小于key,则两者对调,反之i + +,这里的作用是找到第一个比基准数key小的数,并且与基准数key对调,使得小数往后靠。
4 重复2,3 ,直到 i = j。这样key的左边都是比key大的数,右边都是比key小的数。
5 对于key的左右两边,分别进行上述操作,直到每一个部分都是一个数字。
代码如下:
package com.xxc.algorithm.QuickSort;
public class QuickSort {
private int[] array;
public QuickSort(int[] array) {
this.array = array;
}
public void sort() {
quickSort(array,0, array.length-1);
}
public void print() {
for(int i = 0; i < array.length;i++) {
System.out.println(array[i]);
}
}
public void quickSort(int[] src, int begin, int end) {
if (begin < end) {
int key = src[begin]; //将第一个数设置为基准数
int i = begin;
int j = end;
//从大到小排序
while (i < j) {
while(i<j && key>=src[j]) { //找到第一个比基准数小的数
j--;
}
if(i<j) { //把比基准数小的数与基准数对调,使得小数往后挪
int temp = src[j];
src[j] = key;
src[i] = temp;
}
while(i<j && key<=src[i]) { //找到第一个比基准数大的数
i++;
}
if(i<j) { //把比基准数大的数与基准数对调,使得大数往前挪
int temp = src[i];
src[i] = key;
src[j] = temp;
}
}
quickSort(src, begin, i-1);
quickSort(src, i+1, end);
}
}
}
package com.xxc.algorithm.QuickSort;
public class SortTest {
public static void main(String[] args) {
testQuickSort();
}
public static void testQuickSort() {
int[] array = {5,9,1,9,5,3,7,6,1};
QuickSort quickSort = new QuickSort(array);
quickSort.sort();
quickSort.print();
}
}
特点
1 时间复杂度O(n2)平均时间复杂度O(n logn),空间复杂度O(logn)
2 不稳定,相同值的相对位置会改变
3 相同数量级的所有排序算法中,平均性能最好