合并排序的递归实现

来源:互联网 发布:股票软件的数据接口 编辑:程序博客网 时间:2024/06/01 18:58

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

 1 /** 2  * Merge_Sort: 归并排序的递归实现 3  * 注:算法导论上给出的合并排序算法 4  * 递归过程是将待排序集合一分为二, 5  * 直至排序集合就剩下一个元素为止,然后不断的合并两个排好序的数组 6  * T(n) = O(nlgn) 7 **/ 8 #include <stdio.h> 9 #define LEN 810 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         else30             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 + Conquer50         merge_sort(a, start, mid); // 递归划分原数组左半边array[start...mid]51         merge_sort(a, mid+1, end); // 递归划分array[mid+1...end]52         // 合并:Combine53         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就不会有这种问题,所以细节一定要注意。

0 0
原创粉丝点击