对分解与合并的过程分析
合并时数组元素下标的计算推导
/*7.递归归并排序:将已有序的子序列合并,得到完全有序的序列;
*即先使每个子序列有序,再使子序列段间有序。
*若将两个有序表合并成一个有序表,称为二路归并.*/
public static void mergeSort(int[] array) {
mergeSortHelp(array, 0, array.length - 1);
}
private static void mergeSortHelp(int[] array, int low, int high) {
//递归的终止条件
if (low == high) {
return;
}
// 使用类似后序遍历的方式.
// 先把当前的待排序区间拆成两半,
// 递归的对这两个子区间进行归并排序, 保证两个区间有序之后
// 再进行合并
int mid = (low + high) / 2;
mergeSortHelp(array, low, mid);
mergeSortHelp(array, mid + 1, high);
//合并
merge(array, low, mid, high);
}
//合并数组
private static void merge(int[] array, int low, int mid, int high) {
//s1第一个归并段的开始,s2第二个归并段的开始
int s1 = low;
int s2 = mid + 1;
//数组长度
int len = high - low + 1;
// 创建一段临时空间辅助进行归并
// 这个临时空间的长度应该是两个待归并区间的长度之和
int[] tmp = new int[len];
// 这个变量保存着当前 tmpIndex 中的末尾元素的下标
int tmpIndex = 0;
while (s1 <= mid && s2 <= high) {
//array[s1] < array[s2]就是不稳定的排序
if (array[s1] <= array[s2]) {
tmp[tmpIndex] = array[s1];
tmpIndex++;
s1++;
} else {
tmp[tmpIndex] = array[s2];
tmpIndex++;
s2++;
}
}
// 上面的循环结束之后, 两个区间至少有一个是遍历完了的.
// 就把剩下的区间的内容直接拷贝到 output 中即可.
while (s1 <= mid) {
tmp[tmpIndex] = array[s1];
tmpIndex++;
s1++;
}
while (s2 <= high) {
tmp[tmpIndex] = array[s2];
tmpIndex++;
s2++;
}
//合并---最后一步, 把 tmp 中的元素拷贝回原来的区间
for (int j = 0; j < tmp.length; j++) {
array[low + j] = tmp[j];
}
}
/*7.2非递归版的归并排序.*/
public static void mergeSort1(int[] array) {
//gap--表示一组有几个数据
for (int gap = 1; gap < array.length; gap *= 2) {
merge1(array, gap);
}
}
private static void merge1(int[] array, int gap) {
int[] tmp = new int[array.length];
//记录tmp数组的下标位置
int tmpIndex = 0;
int s1 = 0;
int e1 = s1 + gap - 1;
int s2 = e1 + 1;
int e2 = s2 + gap - 1 >=
array.length ? array.length - 1 : s2 + gap - 1;
//当有两个归并段的时候
while (s2 < array.length) {
while (s1 <= e1 && s2 <= e2) {
if (array[s1] <= array[s2]) {
tmp[tmpIndex++] = array[s1++];
} else {
tmp[tmpIndex++] = array[s2++];
}
}
while (s1 <= e1) {
tmp[tmpIndex++] = array[s1++];
}
while (s2 <= e2) {
tmp[tmpIndex++] = array[s2++];
}
//重新确定s1 e1 s2 e2 的位置
s1 = e2 + 1;
e1 = s1 + gap - 1;
s2 = e1 + 1;
e2 = s2 + gap - 1 >=
array.length ? array.length - 1 : s2 + gap - 1;
}
//判断s1是否有数据-》上面第一个循环进不来
while (s1 <= array.length - 1) {
tmp[tmpIndex++] = array[s1++];
}
//拷贝tmp到array
for (int j = 0; j < tmp.length; j++) {
array[j] = tmp[j];
}
}