import java.util.Arrays;
import java.util.Stack;
public class 归并排序 {
public static void main(String[] args) {
int[] arr = {99, 88, 77, 66, 55, 44, 33, 22, 11};
mergeSortStack(arr);
System.out.println(Arrays.toString(arr));
}
public static void mergeSort(int[] arr) {
mergeSort(arr, new int[arr.length], 0, arr.length - 1);
}
private static void mergeSort(int[] arr, int[] temp, int left, int right) {
if (left < right) { //直至剩余一个时,则弹栈,然后就是从最小两个开始合并
int mid = (left + right) / 2;
mergeSort(arr, temp, left, mid);
mergeSort(arr, temp, mid + 1, right);
merge(arr, temp, left, mid, right);
}
}
private static void merge(int[] arr, int[] temp, int left, int mid, int right) {
int i = left; //左边范围指针
int j = mid + 1; //右边范围指针
int k = 0; //temp 指针
while (i <= mid && j <= right) {
if (arr[i] < arr[j]) { //排序,要么左范围数据小,要么右范围数据小
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
// 两个其中之一有一个没有移动完成,则全部放进 temp 排序
while (i <= mid) {
temp[k++] = arr[i++];
}
while (j <= right) {
temp[k++] = arr[j++];
}
// 最后移动到 arr
for (int x = 0; x < k; x++) { //直接小于 k 范围,而不是 temp.length,要的是比较后的元素个数
arr[left++] = temp[x];
}
}
static class Area {
public int left;
public int right;
public boolean isBinary; //重要标识,判断是否已经二分过,没有则继续二分,然后标识 true
public Area (int left, int right) {
this.left = left;
this.right = right;
}
}
static class Merge extends Area {
public int mid;
public Merge(int left, int mid, int right, boolean isBinary) {
super(left, right);
this.mid = mid;
this.isBinary = isBinary;
}
}
public static void mergeSortStack(int[] arr) { //非递归版
Stack<Area> stack = new Stack<>();
stack.push(new Merge(0, (arr.length - 1) / 2, arr.length - 1, false)); //初始化最底层合并对象
int[] temp = new int[arr.length];
while (! stack.isEmpty()) {
Area peek = stack.peek(); //归并需要拿出来看,而不是直接取,最后需要合并
if (peek.isBinary) { //判断是否已二分
if (peek instanceof Merge) { //此时要么是 Merge 对象,要么是 Area 对象
merge(arr, temp, peek.left, ((Merge) peek).mid, peek.right);
stack.pop();
} else { //Area 直接弹栈
stack.pop();
}
} else {
int left = peek.left;
int right = peek.right;
if (left < right) { //直至剩余一个时,则弹栈,然后就是从最小两个开始合并
peek.isBinary = true; //标记已二分操作
int mid = (left + right) / 2;
// 添加对象入栈时,要按常规递归版倒序入栈,把合并对象先压栈,区域对象后入栈,是为了查看区域对象是否已经二分,没有则继续二分
// 最关键是,存储的压栈关系,Area <—— Area <—— Merge <—— Area <—— Area <—— Merge <—— Area <—— Area <—— Merge(这个是最开始入栈的合并对象)
stack.push(new Merge(left, mid, right, true)); //之后的操作一直为是已经二分的状态 true
stack.push(new Area(mid + 1, right)); //右区间
stack.push(new Area(left, mid)); //左区间
} else { //在等于 1 个元素时,直接弹出栈
stack.pop();
}
}
}
}
}
输出
[11, 22, 33, 44, 55, 66, 77, 88, 99]
&spm=1001.2101.3001.5002&articleId=141161203&d=1&t=3&u=aad9e66783ec467e882b315e171058ec)
135

被折叠的 条评论
为什么被折叠?



