快速排序:
快速排序是一种分而治之的思想,把需要排序的序列划分成小的序列,再层层划分直至每个序列只有一个数字为止,而在每次划分中至少能确定一个数字,即基准数的位置,最终完成排序,以下排序均是从小到大进行排序。
一、挖坑法
把左指针所指向的数视为基准数(坑),left为左指针,righ为右指针,左边的数字都比基准数(坑)小;右边的数字都比基准数(坑)大。
每次比较如果右指针满足条件则左移,即 if(nums[right] > temp) right-- ;当不满足条件时,把右指针所指的值赋值给左指针,同时从左指针开始比较,如果满足左指针所在的数据小于基准数if(nums[right] > temp) left++ ,直到left == right结束,而此时left的位置即为基准数的位置,把基准数防至left的位置即可。
第一次交换:考虑到要把基准数作为交换数去比较,如果选择的基准数在左边,则从右边开始比较,如果选择的基准数在右边,从左边开始比较,这样可以保证开始被替换的数字永远是基准数。
左指针不满足条件,将左指针指代的数赋值给右指针指代的数。
同理,右指针进行比较
此时 left = right,而left的位置即为基准数的位置,把left所在的值替换为基准数,完成第一次排序。
......
依次下来,把基准数左边的和右边的作为新排序对象再次进行排序,最终所有的数字都是有序的。
代码示例:
public class QuickSort02 {
public static void qSort(int[] nums) {
qulifier(nums, 0, nums.length - 1);
}
public static void qulifier(int[] nums, int left, int right) {
if (left < right) {
int db = updateAndSwap(nums, left, right);
qulifier(nums, left, db - 1);
qulifier(nums, db + 1, right);
}
}
public static int updateAndSwap(int[] nums, int left, int right) {
int tmp = nums[left];
//当左指针 < 右指针执行
while (left < right) {
//当左指针 < 右指针 且右指针所指的数大于基准数
while (left < right && nums[right] <= tmp){
right--;
}
//右指针指向的数小于基准数 则把左指针所在的数替换为右指针 即提出基准值
if(left < right){
nums[left] = nums[right];
}
//当左指针 < 右指针 且左指针所指的数小于基准数
while (left < right && nums[left] >= tmp){
left++;
}
//当左指针指向的数大于基准数 则把右指针所在的数替换为左指针
if(left < right){
nums[right] = nums[left];
}
//当左指针与右指针重合 即把基准值放置到目标数组正确位置
if(left == right){
nums[left] = tmp;
}
}
return left;
}
public static void show(int[] nums) {
Arrays.stream(nums).forEach(System.out::print);
}
public static void main(String[] args) {
int[] nums = {0,2,3,1,9,8,7,4,6,5};
qSort(nums);
show(nums);
}
}
二、左右指针法
左右指针法思想同挖坑交换法类似,不同的是左右指针法是以交换的方式,而挖坑法是以取代的方式。左指针负责寻找比基准数小的数,如果找到比基准数大的,右指针开始寻找比基准数的,如果找到比基准数小的,把左指针与右指针所指向的数交换。当左指针等于右指针时,左指针的值与基准值交换,完成一次排序,依次类推分为左右两组进行,最终完成排序。
左右指针第一次找到位置并交换:
交换后:
第二次找到位置并交换:
第三次找到位置:当left = right时,确定基准值的位置,把left与right所指向的数与基准值进行交换,完成第一次排序。
代码示例:
public class QuickSort03 {
public static void qSort(int[] nums){
pointSwap(nums,0,nums.length - 1);
}
public static void pointSwap(int[] nums,int left,int right){
if(left < right){
int index = partSwap(nums,left,right);
pointSwap(nums,left,index - 1);
pointSwap(nums,index+1,right);
}
}
public static int partSwap(int[] nums,int left,int right){
int begain = left;
int end = right;
int key = right;
while(begain < end){
while (begain < end && nums[begain] <= nums[key]){
begain++;
}
while (begain < end && nums[end] >= nums[key]){
end--;
}
swap(nums,begain,end);
}
swap(nums,begain,right);
show(nums);
return begain;
}
public static void swap(int[] nums,int leftIndex,int rightIndex){
int temp;
temp = nums[leftIndex];
nums[leftIndex] = nums[rightIndex];
nums[rightIndex] = temp;
}
public static void show(int[] nums){
Arrays.stream(nums).forEach(System.out::print);
System.out.println();
}
public static void main(String[] args) {
int[] nums = {1,3,2,9,6,4,7,8,5,0};
qSort(nums);
show(nums);
}
}
三、前后指针法
前后指针法也是在保证两组数据,一组大于基准数,一组小于基准数,使用两个相邻的指针从左往右开始筛选数据较基准数 key 的比较,其思想是设置一个 now指针,即寻找指针,now指针的作用是寻找比基准数小的数据,prev指针的作用是标记比基准数大的数字。当now指针查找的数据均大于key的值时,now指针前移,即now++,直到now指针所指向的数小于 key 基准数。当now指针查找的数据满足条件,且prev指针与now指针不相邻时,进行交换,即(nums[now] < key )&& ++prev != now时进行交换。
初始位置,now指针从起始位置开始,prev指针在now指针之前,即prev = --now,本次排序从小到大排序。now指针寻找的数为比基准数小的数字,在now指针找到之前,prev指针将保持不动。找到比基准数小的数且now指针与Prev指针不指向同一个数(交换没有意义),则交换now指针与prev指针指向的数。
第一次位移,因为prev == now 不进行交换
第二次位移:prev < now 交换
依次往下交换:
最后当Now指针与key所在的位置相等时,把prev指针前移一位,与key所指向的数交换,最后返回prev的值,即为确定了当前基准数的位置,并开始其他基准数的排序。
代码示例:
public class QuickSort04 {
public static void qSort(int[] nums){
partSort(nums,0,nums.length - 1);
}
private static void partSort(int[] nums, int left, int right) {
if(left < right){
int index = updateAndSwap(nums,left,right);
partSort(nums,left,index - 1);
partSort(nums,index+1,right);
}
}
public static void swap(int[] nums,int index1,int index2){
int tmp;
tmp = nums[index1];
nums[index1] = nums[index2];
nums[index2] = tmp;
}
private static int updateAndSwap(int[] nums, int left, int right) {
int cur = left;
int prev = left - 1;
int key = nums[right];
while (cur < right){
// &&符号当左边检测为假时 不执行右边判断条件
if(nums[cur] < key && ++prev != cur){
swap(nums,cur,prev);
}
cur++;
}
swap(nums,++prev,right);
show(nums);
return prev;
}
public static void show(int[] nums){
Arrays.stream(nums).forEach(System.out::print);
System.out.println();
}
public static void main(String[] args) {
long start = System.currentTimeMillis();
int[] nums = {1,5,6,7,0,3,2,9,8,4};
qSort(nums);
show(nums);
System.out.println(System.currentTimeMillis() - start);
}
}