面试官: 不用递归就不会快速排序了? -_-||: 瞧不起谁呢
面试官: 非递归的方式写一下快速排序?
-_-||: 额...
面试官: 就这?
-_-||: ...
非递归实现快排思路
代码中一层一层的方法调用, 本身就使用了一个方法调用栈. 每次进入一个新方法, 相当于入栈, 每次有方法返回, 相当于出栈.
所以, 可以把原本递归实现转化成一个栈的实现, 在栈中存储每次方法调用的参数.
quickSort的非递归部分实现
非递归实现快排: 在单边循环法基础上演变, 不同的是quickSort().
public static void quickSort(int[] arr, int startIndex, int endIndex) {
// 用一个集合栈来代替递归的函数栈
Stack<Map<String, Integer>> quickSortStack = new Stack<Map<String, Integer>>();
// 数组的下标通过哈希的形式入栈
Map indexParam = new HashMap();
indexParam.put("startIndex", startIndex);
indexParam.put("endIndex", endIndex);
quickSortStack.push(indexParam);
// 循环结束条件:栈为空
while (!quickSortStack.isEmpty()) {
// 栈顶元素出栈,得到起止下标
Map<String, Integer> param = quickSortStack.pop();
// 得到基准元素位置
int standardIndex = partition2(arr, param.get("startIndex"), param.get("endIndex"));
// 根据基准元素分成两部分, 把每一部分的起止下标入栈
if (param.get("startIndex") < standardIndex - 1) {
Map<String, Integer> leftParam = new HashMap<>();
leftParam.put("startIndex", param.get("startIndex"));
leftParam.put("endIndex", param.get("endIndex"));
quickSortStack.push(leftParam);
}
if (param.get("endIndex") > standardIndex + 1) {
HashMap<String, Integer> rightParam = new HashMap<>();
rightParam.put("startIndex", standardIndex + 1);
rightParam.put("endIndex", param.get("endIndex"));
quickSortStack.push(rightParam);
}
}
}
非递归快排的完整实现
/**
* @description: 非递归实现快速排序
* @author: liangyadong
* @date: 2021/7/12 0012 21:08
**/
public class QuickSortNonRecur {
public static void quickSort(int[] arr, int startIndex, int endIndex) {
// 用一个集合栈来代替递归的函数栈
Stack<Map<String, Integer>> quickSortStack = new Stack<Map<String, Integer>>();
// 数组的下标通过哈希的形式入栈
Map indexParam = new HashMap();
indexParam.put("startIndex", startIndex);
indexParam.put("endIndex", endIndex);
quickSortStack.push(indexParam);
// 循环结束条件:栈为空
while (!quickSortStack.isEmpty()) {
// 栈顶元素出栈,得到起止下标
Map<String, Integer> param = quickSortStack.pop();
// 得到基准元素位置
int standardIndex = partition(arr, param.get("startIndex"), param.get("endIndex"));
// 根据基准元素分成两部分, 把每一部分的起止下标入栈
if (param.get("startIndex") < standardIndex - 1) {
Map<String, Integer> leftParam = new HashMap<>();
leftParam.put("startIndex", param.get("startIndex"));
leftParam.put("endIndex", param.get("endIndex"));
quickSortStack.push(leftParam);
}
if (param.get("endIndex") > standardIndex + 1) {
HashMap<String, Integer> rightParam = new HashMap<>();
rightParam.put("startIndex", standardIndex + 1);
rightParam.put("endIndex", param.get("endIndex"));
quickSortStack.push(rightParam);
}
}
}
/**
* 分治(单边循环法)
*
* @param arr 待交换的数组
* @param startIndex 起始下标
* @param endIndex 结束下标
* @return 基准元素的位置
*/
private static int partition(int[] arr, int startIndex, int endIndex) {
// 取第一位元素作为基准元素
int standardValue = arr[startIndex];
// 指针指向数列的起始位置,mark代表小于基准元素的区域边界
int mark = startIndex;
// 遍历数组,如果遍历到的元素小于基准元素: 1. 2.
for (int i = startIndex + 1; i <= endIndex; i++) {
if (arr[i] < standardValue) {
// 1.指针右移一位
mark++;
// 2.并将当前遍历到的元素和指针所指元素交换
int temp = arr[i];
arr[i] = arr[mark];
arr[mark] = temp;
}
}
// 遍历结束,将基准元素和指针指向的元素交换,这一轮宣告结束
arr[startIndex] = arr[mark];
arr[mark] = standardValue;
return mark;
}
public static void main(String[] args) {
int[] arr = {5, 2, 6, 3, 7, 9, 8, 4, 1, 0};
quickSort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr));// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
}
}
思考ing...
单边循环法OK了, 双边循环呢?
习惯沉淀
一线码农的学习见闻与思考
Official Account