ps:快排会有边界问题,所以背一个模板
static void QuickSort(int[] q,int l,int r) {
if(l >= r) {
return;
}
int i = l-1;
int j = r+1;
int medium = nums[l];
while (i<j) {
do i++; while (q[i]<medium); !!这里是易忘点
do j--; while (q[j]>medium);
if (i < j) {
int temp = q[i];
q[i] = q[j];
q[j] = temp;
}
}
//递归排序左边
QuickSort(q, l, j);
//递归排序右边
QuickSort(q, j + 1, r);
}
应用层面剖析
方法形参传值都传边界,创建指针时向外拓一位(也就是左边界-1,右边界+1)方便进行判断
判断的值是 取当前数组的左边界
条件判断
只有指针穿过,或相等,整个数组才是被指针划分开左右两个理想区域(理想区域就是左边都比比较值小,右边都比比较值大)
如果他们卡在了两边的不同点
为什么卡住?
我们先分析一下为什么会卡住,因为指针发现了目标,把指针想象成两个过滤网,有过滤不掉的东西,它就会卡住不走。左指针是因为碰到大的(因为它的任务是将左区域过滤成小的),右指针是因为碰到小的(因为它的任务是把右区域过滤成大的),这个大和小是相对于比较值而言。
卡住了怎么办?
既然左右两个过滤网都碰到了不属于自己的东西,那就互相交换咯(if判断就是来做这个事的)
递归区域划分
右指针最后指到哪,那个地方以及前面整个都是左区域(因为J停的地方就是小的它才会停,如果比比较值大的话它就不会停那了),我们比较值都用了数组左边界,所以 其实它就是不断在排序右区域
注意
中间值不能用右边界,会出现溢出问题,用左边界稳妥。
个人整理
判断
递归总有一个结束判断,当左边界>=有边界,证明数组为空,结束返回
构造指针和中间值
指针往外拓一位(方便移动的时候判断)
比较值为数组左边界索引值(防止溢出)
移动过滤(直到两指针交汇才算这一轮过滤成功)
左指针就是左滤网,它专筛比“比较值”小的值 注:用比较值和指针指向的数组值进行比较
右指针则相反,它专筛比“比较值”大的值
筛完以后如果左指针小于右指针,说明他们遇到茬了,马上交换数组的这两个值。注:交换完了还要再循环,确保交换完以后彻底筛干净
左右区域递归
递归调用方法,分别调用左边界到右指针的,和右指针右边的。
番外
在这个排序思想中,两个指针相等或者越过都是理想情况,因为只有他们两个过滤网都成功过滤了,才会相等或传过。所以如果左指针<=右指针,就是两个过滤网都遇到茬了,交换。简单记忆:判断,构造,移动,递归
ps:今天有点心得,发现c++的指针其实可以用参数来代替,指针就是索引
代码
package com.company;
import java.util.Scanner;
public class QuickSortRepeat {
static void QuickSort(int[] nums,int l,int r){
/*判断*/
if(l>=r){
return;
}
/*构造指针和比较值*/
int i = l-1;
int j = r+1;
int x = nums[l];
/*移动指针并判断*/
while (i<j){
do{ i++;}while(nums[i]<x);
do{ j--;}while(nums[j]>x);
if (i<j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
/*左右区域递归*/
QuickSort(nums,l,j);
QuickSort(nums,j+1,r);
}
public static void main(String[] args) {
/*外界输入*/
Scanner sc = new Scanner(System.in);
int ListSize = sc.nextInt();
int[] nums = new int[ListSize];
String[] strs = sc.next().trim().split(",");
for (int i=0;i<ListSize;i++){
nums[i] = Integer.parseInt(strs[i]);
}
/*调用方法*/
QuickSort(nums,0,nums.length-1);
/*查询*/
for (int i:nums) {
System.out.print(i+",");
}
}
}