import org.junit.Test;
import java.util.Arrays;
import java.util.LinkedList;
public class Sort {
private static class Range{
int begin, end;
Range(int b, int e){
begin = b;
end = e;
}
}
public static <T extends Comparable> void fastSort(T[] array){
// 在这里,不使用系统栈(递归),但其实还是得用栈来完成
LinkedList<Range> stack = new LinkedList<>();
// 分治法开始会产生两个子问题,然后子问题二分四产生子子问题然后四分八,八分十六...
// 直到分成的子问题可以立即被解出,此时就获得了总问题的解
// 快排的层层递归中实际上变化的也只是数组的起始与结束坐标而已
// 此处使用一个Range对象来维护这两个参数
stack.add(new Range(0, array.length - 1));
// 开始模拟递归
while(!stack.isEmpty()){
// 取出栈顶元素做一次快排
Range r = stack.pop();
// 重载函数fastSort(见下方)会返回单次排序后的中心坐标
int mi = fastSort(array, r.begin, r.end);
// 若为-1说明这个子数组已经不能再一分为二了,跳过即可
if(mi == -1){
continue;
}
// 以中心坐标mi为中点分割成左右两个子数组压栈(递归)
stack.add(new Range(r.begin, mi - 1));
stack.add(new Range(mi + 1, r.end));
}
}
private static <T extends Comparable> int fastSort(T[] array, int bIndex, int eIndex){
// 单次快排实现
if(eIndex - bIndex < 1){
return -1;
}
int l = bIndex, r = eIndex;
// 利用一个标志变量控制向左走还是向右走
boolean right = true;
// 获取基准值,这里是以给定数组的 起始下标 上的元素
T c = array[bIndex];
while(l < r){
if(right){
// 从右向左查找一个比基准值小的
if(array[r].compareTo(c) < 0){
// 找到之后翻置标志变量,换方向
right = false;
continue;
}
--r;
}else{
// 先加一次,跳过基准值本身
++l;
// 从左向右查找一个比基准值大的
if(array[l].compareTo(c) > 0){
// 同理,翻置
right = true;
// 交换两个满足条件的元素
swap(array, l, r);
// 这个时候记得把r下标向左移一位(不移也行,但会多一次重复判断)
--r;
}
}
}
// 最后把基准值交换到中心坐标
swap(array, bIndex, l);
// 若是递归代码就很简单,就这么两行,不难看出在递归过程中变化的就是起始与结束坐标
// fastSort(array, bIndex, l - 1);
// fastSort(array, l + 1, eIndex);
return l;
}
private static void swap(Object[] arr, int index0, int index1){
Object temp = arr[index0];
arr[index0] = arr[index1];
arr[index1] = temp;
}
@Test
public void testFastSort(){
Integer[] arr = {6, 1, 2, 7, 9, 3, 4, 5, 10, 8, 85, 100,434, 5, 66, 42, 22, 90};
fastSort(arr);
System.out.println(Arrays.toString(arr));
Integer[] arr2 = {8, 3, 10, 9, 9, 4, 6, 6, 7, 9, 3};
fastSort(arr2);
System.out.println(Arrays.toString(arr2));
}
}
快速排序非递归版 Java实现
于 2022-07-30 14:22:15 首次发布