快速排序是在每一轮挑选一个基准元素,比他大地站左边,比他小的站右边,从而把数列拆分成两部分,假如元素是n个,平均情况下需要logn轮,因此平均实践复杂度是O(nlogn).
1 双边循环法
public static void main(String[] args) {
int[] array = new int[]{2, 1, 5, 6, 7, 8, 9, 10};
quickSort(array, 0, array.length - 1);
System.out.println(Arrays.toString(array));
}
public static void quickSort(int[] arr, int startIndex, int endIndex) {
// 递归结束条件
if (startIndex >= endIndex) {
return;
}
// 获取基准点
int pivotIndex = part(arr, startIndex, endIndex);
// 根据基准点 ,左右部分分别排序
quickSort(arr, startIndex, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, endIndex);
}
/**
* 双边循环法
*
* @param arr 需要交换的数组
* @param startIndex 开始下表
* @param endIndex 结束下表
* @return 基准点
*/
private static int part(int[] arr, int startIndex, int endIndex) {
// 取第一个位置当基准点
int pivot = arr[startIndex];
int left = startIndex;
int right = endIndex;
while (left != right) {
// 右边小的左移动
while (left < right && arr[right] > pivot) {
right--;
}
// 左边大的右移
while (left < right && arr[left] <= pivot) {
left++;
}
//交换位置
if (left < right) {
int p = arr[left];
arr[left] = arr[right];
arr[right] = p;
}
}
// 基准点 与 指针重合点交换
arr[startIndex] = arr[left];
arr[left] = pivot;
return left;
}
- 单边循环法
public static void main(String[] args) {
int[] array = new int[]{2, 1, 5, 6, 7, 8, 9, 10};
quickSort(array, 0, array.length - 1);
System.out.println(Arrays.toString(array));
}
public static void quickSort(int[] arr, int startIndex, int endIndex) {
// 递归结束条件
if (startIndex >= endIndex) {
return;
}
// 获取基准点
int pivotIndex = part2(arr, startIndex, endIndex);
// 根据基准点 ,左右部分分别排序
quickSort(arr, startIndex, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, endIndex);
}
/**
* 单边循环法
*
* @param arr 需要交换的数组
* @param startIndex 开始下表
* @param endIndex 结束下表
* @return 基准点
*/
private static int part2(int[] arr, int startIndex, int endIndex) {
// 取第一个位置当基准点
int pivot = arr[startIndex];
int left = startIndex;
// 从第二个开始比较
for (int i = startIndex + 1; i <= endIndex; i++) {
if (arr[i] < pivot) {
// 左移动 下标++
left++;
int p = arr[left];
arr[left] = arr[i];
arr[i] = p;
}
}
// 基准点 与 指针结束点交换
arr[startIndex] = arr[left];
arr[left] = pivot;
return left;
}
我们知道的:绝大多数的递归的逻辑,都可以用栈来实现,代码中一层一层的方法,本身就是使用了一个方法调用栈,每次进入新的方法,就相当于入栈,每次方法的返回,就相当于出栈
public static void main(String[] args) {
int[] array = new int[]{2, 1, 5, 6, 7, 8, 9, 10};
quickSort2(array, 0, array.length - 1);
System.out.println(Arrays.toString(array));
}
/**
* 栈结构实现
*
* @param arr 数组
* @param startIndex 开始下表
* @param endIndex 结束下表
*/
public static void quickSort2(int[] arr, int startIndex, int endIndex) {
// 使用集合栈来代替递归的函数栈
Stack<Map<String, Integer>> mapStack = new Stack<>();
// 开始和结束 以哈希形式入栈
HashMap<String, Integer> rootParam = new HashMap<>();
rootParam.put("startIndex", startIndex);
rootParam.put("endIndex", endIndex);
mapStack.push(rootParam);
// 栈空结束
while (!mapStack.isEmpty()) {
// 开始结束下表出站
Map<String, Integer> param = mapStack.pop();
// 得到基准元素位置
int pivotIndex = part2(arr, param.get("startIndex"), param.get("endIndex"));
// 根据基准元素分成两部分,每一部分起
if (param.get("startIndex") < pivotIndex - 1) {
HashMap<String, Integer> leftParam = new HashMap<>();
leftParam.put("startIndex", param.get("startIndex"));
leftParam.put("endIndex", pivotIndex - 1);
mapStack.push(leftParam);
}
if (pivotIndex + 1 < param.get("endIndex")) {
HashMap<String, Integer> rightParam = new HashMap<>();
rightParam.put("startIndex", pivotIndex + 1);
rightParam.put("endIndex", param.get("endIndex"));
mapStack.push(rightParam);
}
}
}
/**
* 单边循环法
*
* @param arr 需要交换的数组
* @param startIndex 开始下表
* @param endIndex 结束下表
* @return 基准点
*/
private static int part2(int[] arr, int startIndex, int endIndex) {
// 取第一个位置当基准点
int pivot = arr[startIndex];
int left = startIndex;
// 从第二个开始比较
for (int i = startIndex + 1; i <= endIndex; i++) {
if (arr[i] < pivot) {
// 左移动 下标++
left++;
int p = arr[left];
arr[left] = arr[i];
arr[i] = p;
}
}
// 基准点 与 指针结束点交换
arr[startIndex] = arr[left];
arr[left] = pivot;
return left;
}