使用了两种方法实现归并排序,一种申请了额外了数组空间来存储有序化序列,一种直接利用原先的存储空间,直接进行元素的交换而已。前一种方法比较简单,就是把待排序的序列有序的存储到一个额外的存储空间,后面在对原序列进行赋值替换,而后一种方法要注意元素指针的移动和移动的条件。
算法一:申请额外数组进行中间存储
void Merge(int[] a,int l,int mid,int r){
int temps[] = new int[r-l+1];//创建一个额外的数组来存储a[l...r]的有序序列
int i=l,j=mid+1,flag=0;//i和j分别作为作为待归并排序的两段的起始标记
while(i<=mid && j<=r){//只要有一bian的数据已经完全移植到temps,则循环停止
if(a[i] <=a[j]){//如果左边的数比右边的小,则先赋值给数组temps,并且标记右移一个位置
temps[flag++] = a[i];
i++;
}else{//如果右边的数比左边的小,则先赋值给数组temps,并且标记右移一个位置
temps[flag++] = a[j];
j++;
}
}
while(i<=mid){//说明左边的数还没有完全移到temps数组
temps[flag++] = a[i++];
}
while(j<=r){//说明右边的数还没有完全移到temps数组
temps[flag++] = a[j++];
}
for (int k = 0; k < temps.length; k++) {//把有序序列赋值给a[l...r]数据段
a[l++] = temps[k];
}
}
算法二:直接对原序列进行一定规则的替换
void Merge(int[] a,int l,int mid,int r){
int i,j,temp;//i,j为前段和后段的位置指针
for(i=l,j=mid+1; i<=mid && j<=r;){//循环的条件是i,j不越界
if(a[i] <= a[j]){//如果前段指针指向的元素比后段指针指向的小,则不处理,只是把前段指针后移一个位置
i++;
}else{//说明后段指针指向元素比较小,需要给前段指针指向的元素在后段找一个合适的元素
temp = a[i];
a[i] = a[j];
if((j+1)<=r && a[j+1]<=temp){//考虑一种特殊情况比如前段为7 8 10 后段为 3 4情况,应该对序列进行如何元素交换
int k = j+1;
for (; k <= r && a[k] <= temp; k++) {
a[k-1] = a[k];
}
a[k-1] = temp;
}else{//正常情况下的交换
a[j] = temp;
}
}
}
}
两种算法共用归并的第一步,划分与归并
void MSort(int[] a,int l,int r){
if(l<r){
int mid=(l+r)/2;
MSort(a,l,mid);
MSort(a, mid+1, r);
Merge(a, l, mid, r);
}
}
使用的时候只要把数组和相关参数传入MSort函数即可。比如数组为
int[] list = new int[]{1,12,98,77,101,200,600,999,-87,-9,-1,5,7,3,9,8,4,6};
然后调用MSort(list, 0, list.length-1)即可