思想:
- 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法。
- 将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。
- 若将两个有序表合并成一个有序表,称为二路归并。
总而言之,归并排序总体分为两步:分解与合并
先分解为许多有序的子区间,然后再将这些有序的子区间合并成一个有序区间。见如下图所示:
因此,我们在实现该算法时就分为三步:
- 将区间划分为两部分
- 将这两部分分为有序的子区间
- 将子区间合并成一个有序区间
首先,我们先将整体思路来实现一下,具体如何分解如何合并我们后面一一分析:
代码实现:
public void mergeSortInternal(int[] array, int low, int high) {
if(low >= high)
{
return ;
}
//分割为两部分
int par=(low+high)/2;
mergeSortInternal(array,low,par);
mergeSortInternal(array,par+1,high);
//合并
merge(array,low,par,high);
}
上面代码就是归并排序的思路,也就是上面说的三步:分为两个区间,分解,合并。
接下来就来看看如何将有序区间进行合并的:
merge方法:
先说一下合并方法的思想:
- s1和s2分别从两个区间首元素开始;
- 比较s1和s2对应的元素谁小将谁放到临时数组中并且让下标++,直到所有元素比较完;
- 如果有一个区间还剩有元素,直接添加到临时数组尾部;
- 最后将临时数组中的元素全部搬移到原始数组中;
注意: 搬移元素的时候需要搬移回原位置,从 low 开始(low是原始数组的下标)
我们以上图中6 10和1 7两个区间为例,假设s1代表第一个区间的起始下标(也就是参数low),s2代表第二个区间的起始下标(也就是参数par+1);具体过程如下图所示:
代码实现:
private void merge(int[] array, int low, int par, int high) {
int s1=low;
int s2=par+1;
int length=high-low+1;
int [] tmp=new int[length];
int i=0;//临时数组的下标
//两个区间都有元素
while(s1<=par && s2<=high)
{
if(array[s1]<=array[s2])
{
tmp[i++]=array[s1++];
}else{
tmp[i++]=array[s2++];
}
}
//只有s1区间有元素
while(s1<=par)
{
tmp[i++]=array[s1++];
}
//只有s2区间有元素
while(s2<=high)
{
tmp[i++]=array[s2++];
}
//搬移元素
for(int j=0;j<length;j++)
{
// 需要搬移回原位置,从 low 开始
array[j+low]=tmp[j];
}
}