快速排序本身也有好多种实现方式,实现细节有差异
自己的理解,如有错误地方 欢迎留言
双向指针,while循环
感觉这个是最简洁,最易懂的写法
选取基数在头和尾,差别只有一点, 循环的开始是左边还是右边
//右边为基数时候,左边先行,左边找大的,右边找小的,找到就交换
public void towPoint_Right(int[] ints, int low, int high) {
if(low>=high){
return;
}
int pivot = ints[high];
int i = low;
int k = high;
while (i < k) {
//左小右大, 所以目的是找到大的,然后暂停
while (ints[i] <= pivot && i < k) {
i++;
}
this.swap(ints, i, k);
//目的是找到小的
while (ints[k] >= pivot && i < k) {
k--;
}
this.swap(ints, i, k);
}
this.towPoint_Right(ints, low, k - 1);
this.towPoint_Right(ints, k + 1, high);
}
//左边为基数时候,右边先行,左边找大的,右边找小的,找到就交换
public void towPoint_left(int[] ints, int low, int high) {
if(low>=high){
return;
}
int pivot = ints[low];
int i = low;
int k = high;
while (i < k) {
//目的是找到右边第一个比枢纽值小的,然后交换
while (ints[k] >= pivot && i < k) {
k--;
}
this.swap(ints, i, k);
//目的是找到左边第一个比枢纽值大的,然后交换
while (ints[i] <= pivot && i < k) {
i++;
}
// 小于枢纽的放左边,大于枢纽的放右边
this.swap(ints, i, k);
}
this.towPoint_left(ints, low, k - 1);
this.towPoint_left(ints, k + 1, high);
}
双指针,for循环
/**
* q1:为什么右边先行,基数是数组首元素时候,需要从数组尾部开始
* q2:为什么枢纽值正好位于i=j那个位置上,因为找到需要交换的值时候,枢纽值会被交换到暂停的位置,
最终暂停点的条件就是i=j
* q3:为什么数据重复,能正确排序,因为递归结束条件是只有一个元素
* @param ints
* @param low 0开始
* @param high 最大下标=length-1
*/
public void quick(Integer[] ints, int low, int high) {
if (low >= high) {
return;
}
int pivot = ints[low];
int i = low;
int j = high;
// 右边先行
for (; j >= 0; j--) {
//找到第一个小于枢纽值的元素
if (ints[j] < pivot) {
this.swap(ints, i, j);
//左边开始,找到第一个大于枢纽值的元素
for (; i < ints.length; i++) {
if (ints[i] > pivot) {
this.swap(ints, i, j);
break;
}
if (i >= j) {
break;
}
}
}
// 为啥是末尾判断,因为内部break后 外层循环会再进入一次,导致j少1
if (i >= j) {
break;
}
}
// 中心点左侧,debug时候,会发现,i处就是枢纽值,将i左右2边分开,进行递归,左边的开始永远是0,右边的结尾是数组最大下标
quick(ints, low, i - 1);
// 中心点右侧
quick(ints, i + 1, high);
}
@Test
public void quick_sort1() {
Integer[] ints = {7, 3, 7, 10, 2, 10, 1, 4, 9, 8, 3, 20};
quick(ints, 0, ints.length - 1);
log.info("{}", JSON.toJSONString(ints));
}
单指针
原理,选取最大下标值作为枢纽值,定义一个位置做记录first, 然后循环数组,向后移动,找到比枢纽值小的值, first和当前位置进行交换,first进行加1,最终会到枢纽值的位置.
然后枢纽值和first进行交换. 下面代码为抄袭,默写来的,哈哈
B站地址https://www.bilibili.com/video/BV1GW411H7zh?t=168
quickSortHelper(ints, 0, ints.length - 1);
/**
* 这里做递归
* @param ints
* @param low
* @param high
*/
public void quickSortHelper(int[] ints, int low, int high) {
if (low >= high) {
return;
}
int i = quickSortSinglePoint(ints, low, high);
quickSortHelper(ints, low, i - 1);
quickSortHelper(ints, i + 1, high);
}
/**
* 单向指针移动,返回值是枢纽值所在的位置
* @param ints
* @param low
* @param high
* @return
*/
public int quickSortSinglePoint(int[] ints, int low, int high) {
int first = low;
int pivot = ints[high];
//这里选取最后一个元素作为枢纽值
//比如说数组有7个元素,那么第一次high=6, 这个i循环0-5次,first最大值==6
for (int i = low; i < high; i++) {
if (ints[i] < pivot) {
this.swap(ints, i, first);
first++;
}
}
//最佳的情况,first = high,这里枢纽值和i暂停的位置做交换
this.swap(ints, first, high);
return first;
}