快速排序(自己版本)
快排,面试最喜欢问的排序算法。这是运用分治法的一种排序算法。
快速排序,说白了就是给基准数据找其正确索引位置的过程.
快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。
原理:
如下图所示,假设最开始的基准数据为数组第一个元素23,则首先用一个临时变量去存储基准数据,即tmp=23;然后分别从数组的两端扫描数组,设两个指示标志:i指向起始位置,j指向末尾.
首先从后半部分开始,如果扫描到的值大于基准数据就让j减1,如果发现有元素比该基准数据的值小(如上图中18<=tmp),找到j的位置,
然后从前半部分开始,如果扫描到的值小于基准数据就让i加1,如果发现有元素大于基准数据的值(如下图46=>tmp),记录i的位置,
找到i与j之后进行一个交换
j指针迁移
然后再开始从前往后遍历,直到i=j结束循环,此时i或j的下标就是基准数据23在该数组中的正确索引位置.如下图所示.
基准与正确位置交换
这样一遍走下来,可以很清楚的知道,其实快速排序的本质就是把基准数大的都放在基准数的右边,把比基准数小的放在基准数的左边,这样就找到了该数据在数组中的正确位置.
以后采用递归的方式分别对前半部分和后半部分排序,当前半部分和后半部分均有序时该数组就自然有序了
利用了递归,空间换时间,8w数据0.021s
private static void quickSort(int[] arr, int low, int high) {
if (low < high) {
// 找寻基准数据的正确索引
int index = getIndex(arr, low, high);
// 进行迭代对index之前和之后的数组进行相同的操作使整个数组变成有序
quickSort(arr, low, index - 1);
quickSort(arr, index + 1, high);
}
}
/**
* 找基准最重要的方法,采用的策略是使数组第一个元素作为基准,i与j分别指向首和尾,
* i 与 j 移动 ,互相交换
* 到最后i == j 的时候,将基准与i交换。
* 当时想弄一个动图演示的,但我debug是一样的呀!
*/
private static int getIndex(int[] arr, int low, int high) {
int i = low;
int j = high;
// 基准数据
int tmp = arr[low];
while (i < j) {
// 当队尾的元素大于等于基准数据时,向前挪动j指针
while (i < j && arr[j] >= tmp) {
j--;
}
// 当队首元素小于等于tmp时,向前挪动i指针
while (i < j && arr[i] <= tmp) {
i++;
}
// 上面二个while循环结束,因为分别碰到了比基准小 与 碰到了比基准大的元素。
// 然后进行一个交换。
// 这里可以不用判断 i 是否小于j 如果i==j 再交换,交换的内容都是一样的,增加了if语句可能会造成更多的时间。
swap(arr,i,j);
}
// 跳出循环时i和j相等,此时的i或j就是tmp的正确索引位置
// 由原理部分可以很清楚的知道low位置的值并不是tmp,需要互相交换pivot(第一个元素) 和 应该去的地方
swap(arr,low,i);
return i; // 返回tmp的正确位置
}
// 抽取交换方法
public static void swap(int[]arr,int i,int j){
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
有参考https://blog.csdn.net/nrsc272420199/article/details/82587933的作图
- 代码https://blog.csdn.net/Websphere_zxf/article/details/109013001