// 分两半,各自排序,然后merge(a, l, m, r) [l,m] [m+1,r]
/**
* 归并排序思想: 首先分成两部分,将两部分分别排序,之后 merge 到一起 三个函数(主函数 递归划分 merge)
* */
// 递归方法实现
public static void mergeSort1(int[] a){
// 对一段区间进行排序
process(a,0,a.length-1);
}
// 对一段 闭区间 进行排序
private static void process(int[] a, int l, int r) {
// 区间只有1个数不用排,递归出口
if(r - l <= 0) return;
// 找到中间点
int mid = l + ((r-l)>>1);
// 分别排序
process(a, l, mid);
process(a, mid+1, r);
// 进行merge
merge(a,l,mid,r);
}
private static void merge(int[] a, int l, int mid, int r) {
// 两部分各自的指针
int i = l, j = mid+1;
// 开辟新的空间
int[] temp = new int[r-l+1];
int index = 0;
// 两边都没有遍历完成
while (i<=mid && j<=r){
if (a[i] < a[j]){
temp[index++] = a[i++];
} else {
temp[index++] = a[j++];
}
}
// 将剩下的一边直接加入 (下边两个循环最多执行一个,也可能都不执行)
while (i<=mid) {
temp[index++] = a[i++];
}
while (j<=r) {
temp[index++] = a[j++];
}
// 将temp 拷贝回a
for (int k = l; k<=r; ++k) {
a[k] = temp[k-l];
}
}
// 非递归 步长为1(左组1,右组1) 2 4 6 8 步长不能超过长度 主要是 process 函数的实现
public static void process2(int[] a) {
int step = 1, r = 0, l = 0, mid = 0;
while (step < a.length) {
l = 0;
while (r < a.length) {
// 左半部分已经不够了,说明已经排好了,无需merge,可以停止了
if (a.length - l <= step)
break;
// 确定 mid 值
mid = l + step - 1;
// 确定右边界
r = Math.min(a.length-1, mid+step);
// 开始merge
merge(a, l, mid, r);
// 求下一个区间
l = r + 1;
}
// step 每次的变化 *2
// 但是不能直接×2 否则会溢出, 只能大于不能等于否则会丢解
if (step > a.length/2)
break;
else
step <<= 1;
}
}
归并排序 递归与非递归写法 (运行方式见上篇文章)
最新推荐文章于 2024-11-06 18:34:45 发布