归并排序是冒泡排序的优化算法,它采用了分治法的思想,使用递归将其解决,以数组{0,3,2,9,6}为例
分治法的基本思想:将一个大问题分割成若干个类似的小问题,解决完小问题后再将小问题组合大问题
分:用递归法 取mid=(left+right)/2 先递归左子表再递归右子表 当left>=right时 分割结束
{0,3,2,9,6} left=0,ring=4,mid=2
第一轮分割;
{0,3,2}left=0,right=2,mid=1 {9,6}left=3,right=4,mid=3
第二轮分割:
{0,3}left=0,right=1,mid=1 {2}left=right=2不可继续分割 {9}left=right=3不可继续分割 {6}left=right=4不可继续分割
第三轮分割:
{0}left=right=0不可继续分割 {3}left=right=1不可继续分割 {2}left=right=2不可继续分割 {9}left=right=3不可继续分割 {6}left=right=4不可继续分割
分割完毕 开始合并
第三轮合并到第二轮:{0}{3}=>{0,3}
第二轮合并到到第一轮:{0,3}{2}=>{0,2,3} {9,6}=>{6,9}
第二轮(此时只有两个数组)合并:{0,2,3,6,9}
在合并过程中关键:除了最后一轮合并,每次合并过程处理的都是小数组(即分割过程中的数组) 该数组长度为right-left+1
合并过程:设置左右两个指针,依次遍历左子表和右子表(l<=mid&&r<=right)相应元素的大小,如arr[l]<arr[r]则把arr[l]放进temp中 反之亦然
如果跳出循环还有一边子表没有遍历完 则将改子表剩余元素全部放入temp中(这么做的是因为两边子表都是有序的)
完成以上步骤 再将temp中元素全部拷贝到arr中 除了最后一次是拷贝全部元素,其他时候都是拷贝right-left+1(即处理完的有序段长度)
归并排要额外开一个数组用来保存数据 是空间换时间的算法
完整代码如下:
public static void meregeSort(int[] arr, int left, int right, int[] temp)
{
if (left < right)
{
int mid = (left + right) / 2;
//递归左子表
meregeSort(arr, left, mid, temp);
//递归右子表
meregeSort(arr, mid + 1, right, temp);
//合并
merege(arr, left, right, temp);
}
}
public static void merege(int[] arr, int left, int right, int[] temp)
{
int mid = (left + right) / 2;//以mid为界限两边子表开始比较
int l = left;//左侧子表开始
int r = mid + 1;//右侧子表开始
int t = 0;//temp索引
while (l <= mid && r <= right)
{
if (arr[l] < arr[r])//如果arr[l]<arr[r] 则把arr[l]存到temp中 同时r++
{
temp[t++] = arr[l++];
}
else//如果arr[l] > arr[r] 则把arr[r]存到temp中 同时r++
{
temp[t++] = arr[r++];
}
}
//如果两边子表还有一边没用遍历完 则将没遍历完的子表全部放入temp中(这么做的前提是因为两边子表都是有序的了
//左子表没用遍历完
while (l <= mid)
{
temp[t++] = arr[l++];
}
//右子表没用遍历完
while (r <= right)
{
temp[t++] = arr[r++];
}
//将temp中的数据拷贝到arr中 除了最后一次合并 每次合并都不是拷贝全部数据 而是right-left+1个数据(即传进来的分数组长度)
t = 0;
while (left <= right)
{
arr[left++] = temp[t++];
}
}