快速排序
快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分, 其中一部分记录的关键字均比另一部分的关键字小, 则可分别对这两部分记录继续进行排序,以达到整个序列有序。
算法描述
快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:
- 步骤1:从数列中挑出一个元素,称为 “基准”(pivot );
- 步骤2:重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
- 步骤3:递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序
动图演示
代码实现
package algorithm.sort;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
public class QuickSort {
public static void main(String[] args) {
int[] array = {1, 2, 9, 4, 6, 7, 8, 3, 0, 5};
System.out.println("原始数组:" + Arrays.toString(array));
System.out.println("排序后数组:" + Arrays.toString(QuickSort.quickSort2(array)));
}
//填坑法
private static int[] quickSort1(int[] array) {
int length = array.length;
if (length < 2) {
return array;
}
sort11(array, 0, length - 1);
return array;
}
private static void sort1(int[] array, int left, int right) {
if (left >= right) {
return;
}
//pivot pivət 枢纽
int pivot = array[left];
int index = left;
int rIndex = right;
int lIndex = left;
for (; lIndex < rIndex; rIndex--) {
if (array[rIndex] < pivot) {
array[lIndex] = array[rIndex];
index = lIndex;
lIndex++;
while (lIndex < rIndex && array[lIndex] < pivot) {
lIndex++;
}
if (lIndex != rIndex) {
array[rIndex] = array[lIndex];
} else {
array[rIndex] = pivot;
index = rIndex;
}
}
}
if (lIndex == rIndex) {
array[rIndex] = pivot;
index = rIndex;
}
sort1(array, left, index - 1);
sort1(array, index + 1, right);
}
private static void sort11(int[] array, int left, int right) {
if (left >= right) {
return;
}
//pivot pivət 枢纽
int pivot = array[left];
int index = left;
int rIndex = right;
int lIndex = left;
while (lIndex < rIndex) {
while (lIndex <= rIndex) {
if (array[rIndex] < pivot) {
array[lIndex] = array[rIndex];
index = rIndex;
lIndex++;
break;
}
rIndex--;
}
while (lIndex <= rIndex) {
if (array[lIndex] > pivot) {
array[rIndex] = array[lIndex];
index = lIndex;
rIndex--;
break;
}
lIndex++;
}
}
array[index] = pivot;
sort11(array, left, index - 1);
sort11(array, index + 1, right);
}
//指针法
private static int[] quickSort2(int[] array) {
int length = array.length;
if (length < 2) {
return array;
}
sort2(array, 0, length - 1);
return array;
}
private static void sort2(int[] array, int left, int right) {
if (left >= right) {
return;
}
int pivod = array[left];
int lIndex = left, rIndex = right;
while (lIndex < rIndex) {
while (array[rIndex] > pivod && lIndex < rIndex) {
rIndex--;
}
while (array[lIndex] <= pivod && lIndex < rIndex) {
lIndex++;
}
if (lIndex < rIndex) {
int item = array[rIndex];
array[rIndex] = array[lIndex];
array[lIndex] = item;
}
}
array[left] = array[rIndex];
array[rIndex] = pivod;
sort2(array, left, rIndex - 1);
sort2(array, rIndex + 1, right);
}
//指针发 + 随机pivot
private static int[] quickSort3(int[] array) {
int length = array.length;
if (length < 2) {
return array;
}
return array;
}
//栈的实现
private static int[] quickSort4(int[] array) {
int length = array.length;
if (length < 2) {
return array;
}
sort4(array, 0, length - 1);
return array;
}
private static void sort4(int[] array, int left, int right) {
// 用一个集合栈来代替递归的函数栈
Stack<Map<String, Integer>> quickSortStack = new Stack<Map<String, Integer>>();
Map rootParam = new HashMap();
rootParam.put("startIndex", left);
rootParam.put("endIndex", right);
quickSortStack.push(rootParam);
while (!quickSortStack.isEmpty()) {
// 栈顶元素出栈,得到起止下标
Map<String, Integer> param = quickSortStack.pop();
// 得到基准元素位置
int pivotIndex = partition(array, param.get("startIndex"), param.get("endIndex"));
// 根据基准元素分成两部分, 把每一部分的起止下标入栈
if (param.get("startIndex") < pivotIndex - 1) {
Map<String, Integer> leftParam = new HashMap<String, Integer>();
leftParam.put("startIndex", param.get("startIndex"));
leftParam.put("endIndex", pivotIndex - 1);
quickSortStack.push(leftParam);
}
if (pivotIndex + 1 < param.get("endIndex")) {
Map<String, Integer> rightParam = new HashMap<String, Integer>();
rightParam.put("startIndex", pivotIndex + 1);
rightParam.put("endIndex", param.get("endIndex"));
quickSortStack.push(rightParam);
}
}
}
private static int partition(int[] arr, int startIndex, int endIndex) {
// 取第一个位置的元素作为基准元素
int pivot = arr[startIndex];
int left = startIndex;
int right = endIndex;
while (left < right) {
//控制right指针比较并左移
while (left < right && arr[right] > pivot) {
right--;
}
//控制left指针比较并右移
while (left < right && arr[left] <= pivot) {
left++;
}
//交换left和right指向的元素
if (left < right) {
int p = arr[left];
arr[left] = arr[right];
arr[right] = p;
}
}
//pivot和指针重合点交换
int p = arr[left];
arr[left] = arr[startIndex];
arr[startIndex] = p;
return left;
}
}
算法分析
- 最佳情况:T(n) = O(nlogn)
- 最差情况:T(n) = O(n2)
- 平均情况:T(n) = O(nlogn)