目录
快速排序原理
原理
以数组中某个数作为基准数(可任选),将数组分为大于等于基准数和小于等于基准数的两个部分,然后在将这两个部分分别重复上述操作(分治)。
分组方法
1.定义左右指针,分别设置为数组的开头和结尾;
2.以左指针开始依次向右遍历数组,找出第一个大于等于基准值的数;
3.以右指针开始依次向左遍历数组,找出第一个小于等于基准值的数;
4.如果左指针 < 右指针,分组未结束,交换左右游标对应数组值,以保证数组被分为大于等于基准数和小于等于基准数的两个部分,将左右游标分别向右左移动一位,重复3,4操作;
5.如果左游标>=右游标,左游标左边的数据均大于等于基准值,右游标右边的数据均大于等于基准值,且此时【左指针=右指针或右指针 + 1】(后续边界问题证明),说明分组完成,退出循环;
代码模板(java)
public static void quicklySort(int[] arr, int left, int right) {
if(left <= right) return;
int temp = arr[(left + right) >> 1];//基准值
int i = left - 1, j = right + 1;//左右游标
while(i < j) {
do i ++; while(arr[i] < temp);
do j --; while(arr[j] > temp);
if(i < j) {
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
quicklySort(arr, left, j);
quicklySort(arr, j + 1, right);
}
边界处理和注意事项
一、为什么使用do…while循环遍历数组
因为在交换后和左右遍历数组都需要对指针左右移动(即–和++)
使用do…while循环可以简化代码
二、为什么左右指针遍历循环条件不能带等号
因为如果带了等号,且基准值temp为最大值或最小值时,会导致左指针或右指针遍历整个数组,且始终满足遍历循环条件,最后导致数组越界。
三、分组过程循环结束后【左指针=右指针或右指针 + 1】
假设(右指针, 左指针)区间中含有数值
对于[left, 左指针)区间,value值均大于等于temp基准值
对于(右指针, right]区间,value均小于等于temp;
故在(右指针, 左指针)区间,value等于temp;
又因为在分组完成的此次循环过程开始前必定满足左指针 < 右指针,故在此次循环中左右指针去遍历数组过程中均会遍历至(右指针, 左指针)区间(循环结束后的左右指针),又其区间value等于temp,会使遍历循环中断,左右指针在[left, 左指针)区间内,矛盾,故(右指针, 左指针)区间中不含有数值,即【左指针=右指针或右指针 + 1】
四、基准值和分组情况的选择
分组情况:
1.[left, j]与[j + 1, right]
2.[left, i - 1]与[i, right]
3.[left, j]与[i, right]
基准值情况:
1.arr[left]或arr[left + right >> 1]:基准值在数组左半区域
2.arr[right]或arr[left + right + 1 >> 1]:基准值在数组右半区域
注:1中当数组区间只含两个数时left=left + right >> 1,故将二者归一类,2中同理
两者选择:
1.当基准值为left时,且此时arr[left]为区间唯一最大值,分组后左右指针i,j均等于left,使用2,3分组情况等同于[left, left - 1]与[left, right] 和[left, left]与[left, right],都含有[left, right],会导致后续无限递归,故只能使用1分组,即基准值1只能对应分组1
2.当基准值为right时,同理可知,只能使用2分组,即基准值2只能对应分组2