package com.basic.order;
import java.util.Arrays;
import java.util.Stack;
//最好、平均是o(nlgn)、最坏都是o(n^2),不稳定
public class QuickSort {
// 快慢指针法:数组前后各设置两个指针,左指针(从左向右走)遇到第一个比基准值大的数停下
// 右指针(从右向左走)遇到第一个比基准值小的数停下,然后交换两个指针指的值
// 如果基准定在左边一定要先动右指针,反之亦然
public static void quickSort(int[] arr, int low, int high) {
if (arr == null || arr.length <= 0 || low >= high)
return;
// 左右指针
int left = low;
int right = high;
// 基准位置的值
int index = left;
int temp = arr[left];
while (left < right) {
// 右指针(从右向左走)
while (left < right && arr[right] >= temp) {
right--;
}
// 左指针(从左向右走)
while (left < right && arr[left] <= temp) {
left++;
}
swap(arr, left, right);
}
swap(arr, right, index);
quickSort(arr, low, left - 1);
quickSort(arr, left + 1, high);
}
// 快排递归方法(挖坑),以某个数作为基数,划分成数组,左边子数组每个元素都小于右边数组,挖坑法
public static void quickSort2(int[] arr, int low, int high) {
if (arr == null || arr.length <= 0 || low >= high)
return;
int left = low;
int right = high;
// 挖坑1:保存基准的值
int temp = arr[left];
while (left < right) {
while (left < right && arr[right] >= temp) { // 坑2:从后向前找到比基准小的元素,插入到基准位置坑1中
right--;
}
arr[left] = arr[right];
while (left < right && arr[left] <= temp) { // 坑3:从前往后找到比基准大的元素,放到刚才挖的坑2中
left++;
}
arr[right] = arr[left];
}
arr[left] = temp; // 基准值填补到坑3中,准备分治递归快排
System.out.println(Arrays.toString(arr));
quickSort2(arr, low, left - 1);
quickSort2(arr, left + 1, high);
}
public static void swap(int[] array, int low, int high) {
int temp = array[low];
array[low] = array[high];
array[high] = temp;
}
// 快排非递归实现
/**
* 非递归
*/
public static void qSort2(int[] a, int low, int high) {
int pivot;
if (low >= high)
return;
Stack<Integer> stack = new Stack<Integer>();
stack.push(low);
stack.push(high);
while (!stack.empty()) {
// 先弹出high,再弹出low
high = stack.pop();
low = stack.pop();
pivot = partition(a, low, high);
// 先压low,再压high
if (low < pivot - 1) {
stack.push(low);
stack.push(pivot - 1);
}
if (pivot + 1 < high) {
stack.push(pivot + 1);
stack.push(high);
}
}
}
/**
* 递归调用
*/
public static void qSort(int[] a, int low, int high) {
int pivot;
if (low >= high)
return;
// 原始递归操作
// pivot = partition(a, low, high); // 将数列一分为二
// qSort(a, low, pivot - 1); // 对低子表排序
// qSort(a, pivot + 1, high); // 对高子表排序
// 优化递归操作
while (low < high) {
pivot = partition(a, low, high); // 将数列一分为二
qSort(a, low, pivot - 1); // 对低子表排序
low = pivot + 1;
}
}
/**
* 对数组a中下标从low到high的元素,选取基准元素pivotKey, 根据与基准比较的大小,将各个元素排到基准元素的两端。 返回值为最后基准元素的位置
*/
public static int partition(int[] a, int low, int high) {
// 三数取中,将中间元素放在第一个位置
if (a[low] > a[high])
swap(a, low, high);
if (a[(low + high) / 2] > a[high])
swap(a, (low + high) / 2, high);
if (a[low] < a[(low + high) / 2])
swap(a, (low + high) / 2, low);
int pivotKey = a[low]; // 用第一个元素作为基准元素
while (low < high) { // 两侧交替向中间扫描
while (low < high && a[high] >= pivotKey)
high--;
a[low] = a[high];
// swap(a, low, high); //比基准小的元素放到低端
while (low < high && a[low] <= pivotKey)
low++;
a[high] = a[low];
// swap(a, low, high); //比基准大的元素放到高端
}
a[low] = pivotKey; // 在中间位置放回基准值
return low; // 返回基准元素所在位置
}
public static void main(String[] args) {
int[] array = { 4, 1, 7, 6, 9, 2, 8, 0, 3, 5 };
// quickSort(array, 0, array.length - 1);
// quickSort2(array, 0, array.length - 1);
qSort(array, 0, array.length - 1);
// qSort2(array,0, array.length - 1);
System.out.println(Arrays.toString(array));
}
}