/**
* 快排概念:
* 快排也属于交换排序,通过元素之间的比较和交换位置来达到排序的目的;在每一轮挑选一个基准元素,并让其他比它大的元素移动到数列一边,
* 比它小的元素移动到数组的另一边,从而将数组拆成两个部分,这种思路叫做分治法
* <p>
* 时间复杂度:
* 原数组在分支法的思想下,每一轮都会被拆分为两部分,所以遍历的轮数为logn,每一轮的比较和交换需要把数组全部遍历一遍,
* 这个时间复杂度是O(n),所以总的平均时间复杂度是O(nlogn)
* 但是如果将原本逆序的数列排序成顺序数列,整个数列并没有被分成两半,每一轮都只确定来基准元素的位置,数列的第一个元素要么是最大值要么是最小值,
* 无法发挥分支法的优势,这个时候快速排序需要进行n轮,时间复杂度退化为O(n平方)。
* 解决思路是:随机选择一个元素作为基准元素
*/
public class QuickSort {
/**
* 递归的方式
*
* @param arr
* @param startIndex
* @param endIndex
*/
public static void quickSort(int[] arr, int startIndex, int endIndex) {
if (arr == null || startIndex >= endIndex) {
return;
}
//得到基准元素位置
int pivotIndex = partition(arr, startIndex, endIndex);
//根据基准元素位置分成两部分进行递归
quickSort(arr, startIndex, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, endIndex);
}
/**
* 循环方式
* 引入一个存储Map类型元素的栈,用于存储每一次交换时的起始下标和结束下标
* 每一次循环,都会让栈顶元素出栈,通过partition方法方法进行分支,并且按照基准元素的位置分成左右两部分,左右两部分再分别入栈。
* 当栈为空时,说明排序已经完毕,推出循环
*/
public static void quickSort2(int[] arr, int startIndex, int endIndex) {
Stack<Map<String, Integer>> stack = new Stack<>();
Map<String, Integer> root = new HashMap<>();
root.put("startIndex", startIndex);
root.put("endIndex", endIndex);
stack.push(root);
while (!stack.isEmpty()) {
Map<String, Integer> item = stack.pop();
int pivotIndex = partition(arr, item.get("startIndex"), item.get("endIndex"));
if (item.get("startIndex") < pivotIndex - 1) {
Map<String, Integer> left = new HashMap<>();
left.put("startIndex", item.get("startIndex"));
left.put("endIndex", pivotIndex - 1);
stack.push(left);
}
if (pivotIndex + 1 < item.get("endIndex")) {
Map<String, Integer> right = new HashMap<>();
right.put("startIndex", pivotIndex + 1);
right.put("endIndex", item.get("endIndex"));
stack.push(right);
}
}
}
/**
* 选择基准元素位置:(单边循环法)
* 首先选定基准元素 pivot,同时设置一个mark指针指向数列起始位置,这个mark指针代表小于基准元素的区域边界
* 接下来从基准元素的下一个位置开始遍历数组
* 如果遍历到的元素大于基准元素,则继续往下遍历
* 如果遍历到的元素小于基准元素,需要做两件事情。
* 第一:将mark元素向右移动1位,因为小于pivot基准元素的区域边界增大了1
* 第二:将遍历到的最新的元素和mark位置指针所在的元素互换位置,因为最新遍历的元素归属于小于pivot的区域
*
* @param arr
* @param startIndex
* @param endIndex
* @return
*/
public static int partition(int[] arr, int startIndex, int endIndex) {
int pivot = arr[startIndex];
int mark = startIndex;
for (int i = startIndex + 1; i <= endIndex; i++) {
if (arr[i] < pivot) {
mark++;
int temp = arr[mark];
arr[mark] = arr[i];
arr[i] = temp;
}
}
arr[startIndex] = arr[mark];
arr[mark] = pivot;
return mark;
}
public static void main(String[] args) {
int[] arr = {4, 4, 6, 5, 3, 2, 8, 1};
quickSort2(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr));
}
}