基本思想
快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
算法描述
快速排序使用分治法来把一个串(名单)分为两个子串(子列表)具体算法描述如下:
- 会把数组当中的一个数当成基准数
- 一般会把数组中最左边的数当成基准数,然后丛两边进行检索。丛右边检索比基准数小的,
然后左边检索比基准数大的。如果检索到了,就停下,然后交换这两个元素,然后继续检索。
基本算法
①:首先找到一个基准数 temp = 5
②:先移动右边的 指针 j ,找到第一个小于 5 的数 也就是 1
然后在移动 执行 i ,找到第一个大于 5 的数 也就是 6
然后进行交换
③:i 和 j 一旦相遇,就停止检索 。 把基准数和相遇位置为树进行交换
④:第一次排序完毕,排序完成以后我们会发现排序的左边比基准数小,右边比基准数大
代码展示:
public class Sort{
public static void main(String[] args) {
int[] arr = new int[] {5,6,3,2,7,1,8};
quickSort(arr,0,arr.length -1);
System.out.println(Arrays.toString(arr));
}
public static void quickSort(int[] arr,int left,int right) {
//定义变量保存基准数
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;
}
}
递归
同学们我们可以看到是只能是第一轮排序,我们的顺序还是没有排好,但是我们也可以发现一个规律就是在基准数左边的数据比基本数小,右边的都比基准数大。如果我们把左右两边的数据都看成一个新的数组,那么这个新数组和原来的数据会经历同样的方式进行排序,那么这是用递归的最好的案例。
分析递归表达式和递归出口
从上一张图当中我么可以看出我们需要将整个数据根据我们原来的游标i或j分成左右两部分,那我们的递归关系是不是可以写成:
只有数据拆分到只有一个的情况我们才能说每个序列都是有序的
而用代码实现就是:
quickSort(arr,left,i-1);
quickSort(arr,i+1,right);
最终代码
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));
}
/**
* 定义方法,实现快速排序
* : f(arr ,right ,i-1)
* 递归关系 : f(arr, right ,left)
* : f(arr ,i+1 ,left)
* 递归出口 : right <= left
* @param arr 数组
* @param left
* @param right
*/
public static void quickSort(int arr[],int left,int right) {
//这里可以写 == ,但是由于我们最后是mid+1 和 mid -1的操作所哟这个地方只能是>=
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, i + 1, right);
}
}