您的位置:首页 > 编程语言 > Java开发

合并排序的递归实现

2015-07-23 15:49 501 查看
之前在博客上偶然看到一篇介绍合并排序递归实现的文章,作者给出了合并排序递归实现的代码,说用的是算法导论的思想,我看了一下代码,思路是算法导论给出的没错,但是递归条件写的有问题,作者给出的代码如下:

1 /**
2  * Merge_Sort: 归并排序的递归实现
3  * 注:算法导论上给出的合并排序算法
4  * 递归过程是将待排序集合一分为二,
5  * 直至排序集合就剩下一个元素为止,然后不断的合并两个排好序的数组
6  * T(n) = O(nlgn)
7 **/
8 #include <stdio.h>
9 #define LEN 8
10
11 // 合并
12 void merge(int a[], int start, int mid, int end)
13 {
14     int n1 = mid - start + 1;
15     int n2 = end - mid;
16     int left[n1], right[n2];
17     int i, j, k;
18
19     for (i = 0; i < n1; i++) /* left holds a[start..mid] */
20         left[i] = a[start+i];
21     for (j = 0; j < n2; j++) /* right holds a[mid+1..end] */
22         right[j] = a[mid+1+j];
23
24     i = j = 0;
25     k = start;
26     while (i < n1 && j < n2)
27         if (left[i] < right[j])
28             a[k++] = left[i++];
29         else
30             a[k++] = right[j++];
31
32     while (i < n1) /* left[] is not exhausted */
33         a[k++] = left[i++];
34     while (j < n2) /* right[] is not exhausted */
35         a[k++] = right[j++];
36 }
37
38 // merge_sort():先排序,再合并
39 void merge_sort(int a[], int start, int end)
40 {
41     int mid;
42     if (start < end)
43     {
44         mid = (start + end) / 2;
45         printf("sort (%d-%d, %d-%d) %d %d %d %d %d %d %d %d\n",
46                start, mid, mid+1, end,
47                a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
48
49         // 分解 + 解决:Divide + Conquer
50         merge_sort(a, start, mid); // 递归划分原数组左半边array[start...mid]
51         merge_sort(a, mid+1, end); // 递归划分array[mid+1...end]
52         // 合并:Combine
53         merge(a, start, mid, end); // 合并
54
55         printf("merge (%d-%d, %d-%d) to %d %d %d %d %d %d %d %d\n",
56                start, mid, mid+1, end,
57                a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
58     }
59 }
60
61 int main(void)
62 {
63     int a[LEN] = { 5, 2, 4, 7, 1, 3, 2, 6 };
64     merge_sort(a, 0, LEN-1);
65
66     return 0;
67 }

在merge_sort方法内并没有给出递归的出口,所以我验证了一下这段代码,结果stackoverflow了,原因很简单,递归没有出口会一直在最底层的merge那里徘徊,自己又尝试着写了java版本,代码如下:

package testfile;

public class testmerge{  
 

    public static void main(String[] args) {  

        int[] data = new int[] { 5, 3, 6, 2, 1, 9, 4, 8, 7 };  

        print(data);  

        mergeSort(data);  

        System.out.println("排序后的数组:");  

        print(data);  

    }  

  

    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);  

      

    }  

 
public static void merge(int [] a,int start,int mid,int end){
int n1=mid-start+1;
int n2=end-mid;
int [] left=new int[n1];
int [] right=new int[n2];
int i,j;
for(i=0;i<n1;i++){
left[i]=a[start+i];
}

for(j=0;j<n2;j++){
right[j]=a[mid+j+1];
}

i=0;j=0;
int k=start;
while(i<n1&&j<n2){
if(left[i]<right[j]){
a[k++]=left[i++];

}
else{
a[k++]=right[j++];
}
}

while(i<n1){
a[k++]=left[i++];
}

while(j<n2){
a[k++]=right[j++];
}

    }  

  

    public static void print(int[] data) {  

        for (int i = 0; i < data.length; i++) {  

            System.out.print(data[i] + "\t");  

        }  

        System.out.println();  

    }  

  



可以看到递归部分的return语句。经验证这个是可以跑出结果的。另外说一句自己写的时候遇到的一个小bug,在merge方法第一层while的if判断条件里,我一开始写的时间并没有用else,而是写了if(left[i]>right[j]),j结果就有了outofbounds错误,原因是在前面的if执行后i的值已经加了1,所以如果前方的if条件里left[i]是left数组的最后一个函数,那么再加1之后肯定就越界了,而用else就不会有这种问题,所以细节一定要注意。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息