您的位置:首页 > 其它

递归和非递归实现归并排序

2017-04-26 18:23 246 查看
1、递归实现归并排序

递归排序其实也是利用了完全二叉树的结构形式,所以时间复杂度和logN挂钩的。具体递归版的归并排序呢,看下面的代码:

public class MS {

public static void main(String[] args) {
int[] s = new int[] { 5, 3, 6, 2, 1, 9, 4, 8, 7 };
print(s);
mergeSort(s);
System.out.println("排序后的数组:");
print(s);

}

public static void mergeSort(int[] data) {
sort(data, 0, data.length - 1);
}

public static void sort(int[] data, int left, int right) {
if (left >= right)
return;
// 找出中间索引
int center = (left + right) / 2;
// 对左边数组进行递归
sort(data, left, center);
// 对右边数组进行递归
sort(data, center + 1, right);
// 合并
merge(data, left, center, right);
print(data);
}

/**
* 将两个数组进行归并,归并前面2个数组已有序,归并后依然有序
*
* @param data
*            数组对象
* @param left
*            左数组的第一个元素的索引
* @param center
*            左数组的最后一个元素的索引,center+1是右数组第一个元素的索引
* @param right
*            右数组最后一个元素的索引
*/
public static void merge(int[] data, int left, int center, int right) {
// 临时数组
int[] tmpArr = new int[data.length];
// 右数组第一个元素索引
int mid = center + 1;
// third 记录临时数组的索引
int third = left;
// 缓存左数组第一个元素的索引
int tmp = left;
while (left <= center && mid <= right) {
// 从两个数组中取出最小的放入临时数组
if (data[left] <= data[mid]) {
tmpArr[third++] = data[left++];
} else {
tmpArr[third++] = data[mid++];
}
}
// 剩余部分依次放入临时数组(实际上两个while只会执行其中一个)
while (mid <= right) {
tmpArr[third++] = data[mid++];
}
while (left <= center) {
tmpArr[third++] = data[left++];
}
// 将临时数组中的内容拷贝回原数组中
// (原left-right范围的内容被复制回原数组)
while (tmp <= right) {
data[tmp] = tmpArr[tmp];
tmp++;
}
}

public static void print(int[] data) {
for (int i = 0; i < data.length; i++) {
System.out.print(data[i] + " ");
}
System.out.println();
}

}


运行结果如下:

5 3 6 2 1 9 4 8 7
3 5 6 2 1 9 4 8 7
3 5 6 2 1 9 4 8 7
3 5 6 1 2 9 4 8 7
1 2 3 5 6 9 4 8 7
1 2 3 5 6 4 9 8 7
1 2 3 5 6 4 9 7 8
1 2 3 5 6 4 7 8 9
1 2 3 4 5 6 7 8 9
排序后的数组:
1 2 3 4 5 6 7 8 9


2、非递归实现归并排序

由于递归的过程中要用到栈,那么这无疑会增加额外的时间和空间消耗,因此,在选择时,有限选择非递归版的归并算法。具体代码如下:

package 排序;
//非递归实现归并排序
public class NewMS {

public static void main(String[] args) {
int[] s = new int[] { 5, 3, 6, 2, 1, 9, 4, 8 ,7};
print(s);
MergeSort2(s);
System.out.println("排序后的数组:");

print(s);
}

private static void MergeSort2(int[] s) { //该函数的作用是让数组中的元素以k进行变步长迭代
int k=1;
while(k<s.length){
MergePass(s,k,s.length-1); //MergePass函数的作用是在给定步长k的情况下,实现局部合并
k=2*k;  //k是以1、2、4、8、16为步长的,当然16步长无法实现
}

}

private static void MergePass(int[] s, int k, int len) {
int i=0;
while(i<=len-2*k+1){//此处循环的目的是两两归并
Merge(s,i,i+k-1,i+2*k-1);
i=i+2*k;
print(s);
}
if(i<len-k+1){//判断是否有落单的数据,如果有的话直接将其和前面相邻的一组数据进行归并
Merge(s,i,i+k-1,len);
print(s);
}
}

private static void Merge(int[] s, int left, int m, int right) {//此部分为归并代码块
int[] tmp=new int[s.length];
int k=left;
int third=left;
int j=m+1;
while(left<=m&&j<=right){
if(s[left]<s[j]){
tmp[k++]=s[left++];
}else{
tmp[k++]=s[j++];
}
}
while(left<=m){
tmp[k++]=s[left++];
}
while(j<=right){
tmp[k++]=s[j++];
}
while(third<=right){
s[third]=tmp[third];
third++;
}

}

private static void print(int[] s) {
for(int i=0;i<s.length;i++){
System.out.print(s[i]+" ");
}
System.out.println();
}

}


运行结果如下:

5 3 6 2 1 9 4 8 7
3 5 6 2 1 9 4 8 7
3 5 2 6 1 9 4 8 7
3 5 2 6 1 9 4 8 7
3 5 2 6 1 9 4 8 7
2 3 5 6 1 9 4 8 7
2 3 5 6 1 4 8 9 7
1 2 3 4 5 6 8 9 7
1 2 3 4 5 6 7 8 9
排序后的数组:
1 2 3 4 5 6 7 8 9


以上就是关于归并排序的程序部分,望共享。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: