基本思想
快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
算法描述
快速排序使用分治法来把一个串(名单)分为两个子串(子列表)具体算法描述如下:
1、会把数组当中的一个数当成基准数
2、一般会把数组中最左边的数当成基准数,然后丛两边进行检索。丛右边检索比基准数小的,然后左边检索比基准数大的。如果检索到了,就停下,然后交换这两个元素,然后继续检索。
3、递归地(递归)把小于基准值元素的子数列和大于基准值元素的子数列排序 。
图解
初始状态下的一个数组,有left标志与right标志分别在最左右两边
选定第一个数,即8为指标right先开始运动
第一次判断right所在位置44,44>8,不变,指针向左
第二次判断right所在位置3,3<8,交换两指针位置
之后又left指针向右移动,因为3刚交换完位置,此时指针指向的是21,21>8,交换位置
11>8位置不变
7<8交换位置
left向右走后,此时left与right指针相同和,第一次交换结束
此时我们可以看到我们的数字8,已经放在了有序数组时他的所在位置且其左边的数都比8小,右边的数都比8大,此时我们只需要吧左边和右边看成两个数组,重复操作即可
代码
public class QuickSort {
public static void main(String[] args) {
int[] arr = new int[] {6,1,2,7,9,3,4,5,10,8};
quickSort(arr,0,arr.length -1);
System.out.println(Arrays.toString(arr));
}
public static void quickSort(int arr[],int left,int right) {
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从右往左移动
}
// i 从左向右检索
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相遇了,就停止检索
//交换基准数和这个相遇位置的元素进行交换
arr[left] = arr[i];
//把基准数赋值给相遇位置的元素
arr[i] = base;
//交换完成之后基准数就归位了 左边的数字都比他小 右边的都比他大
//下一步该排基准数的左边
quickSort(arr, left, i -1);
//排右边
quickSort(arr, j+1, right);
}
}
快速排序如何优化
1、三数取中
在取基准数时,不直接取第一个,而是取最左left,中间center,最右right三个数,经过比较后,把最小值放在left上,最大值放在right上,中间的那个值与left+1位置上的值交换位置并选为基准数,然后在left+2到right+1之间进行比较,既可以防止越界,又使基准数较为合理
2、改用插排
在处理大数据的时候,通常会在n小的时候改用插排而不用快排(n通常是10),因为在数据小的时候插排比快排快。