合并排序递归

时间:2015-09-07 20:05:49

标签: java algorithm mergesort

这是关于Merge Sort的Java编程简介中的代码。此方法使用递归实现。

public class MergeSort {
  2    /** The method for sorting the numbers */
  3    public static void mergeSort(int[] list) {
  4      if (list.length > 1) {
  5        // Merge sort the first half
  6        int[] firstHalf = new int[list.length / 2];
  7        System.arraycopy(list, 0, firstHalf, 0, list.length / 2);
  8        mergeSort(firstHalf);
  9  
 10        // Merge sort the second half
 11        int secondHalfLength = list.length - list.length / 2;
 12        int[] secondHalf = new int[secondHalfLength];
 13        System.arraycopy(list, list.length / 2,
 14          secondHalf, 0, secondHalfLength);
 15        mergeSort(secondHalf);
 16  
 17        // Merge firstHalf with secondHalf into list
 18        merge(firstHalf, secondHalf, list);
 19      }
 20    }

我的问题:在第8行调用递归方法回到“mergeSort”?如果从方法的开头运行,将再次创建“firstHalf”数组,长度将缩短一半。我认为“firstHalf”无法再次创建,如果已经定义了数组,则不应更改长度。

以下是整个代码链接:Merge Sort Java

3 个答案:

答案 0 :(得分:4)

这是初学者的思维方式。是的,当我以前遇到这个时,我的想法完全相同。我无法相信相同的数组大小可以动态更改。理解这一点,在下面的代码中,array l and array r创建了every recursive call的不同大小。不要混淆于此。

是的,对于像你我这样的初学者来说,相同的数组大小永远不可能动态变化。但是,有一个例外,也有例外。随着我们的前进,我们会经常看到它们。

  

它的递归,在递归中,事物会动态地改变这一切   更改存储在调用堆栈中。

它令人困惑,但如果你仔细考虑它真的很有趣。它的深刻。合并排序可以以完全不同的方式实现,但递归的基本概念是相同的。不要在这里感到困惑,你最好按照另一种方式去做,video:

合并排序首先采用列表或数组。让我们想象一下

a.length; #lenght of an array is 8

现在最终目标是递归地拆分数组,直到达到没有元素的点(只有一个)。还有single element is always sorted

请参阅以下代码中的基本案例:

if(a.length<2) /*Remember this is the base case*/
        {
            return;
        }

一旦达到单个元素,就将它们排序并合并。这样您就可以获得一个易于合并的完整排序数组。我们做所有这些无意义的唯一原因是获得一个更好的运行时算法 O(nlogn)。

因为,所有其他排序算法(insertion, bubble, and selection)将采用 O(n2),这确实太多了。因此,人类必须找到更好的解决方案。它是人类的需要,非常重要。我知道它很烦人,我已经经历了这种无意识的。

请在尝试之前对递归进行一些研究。清楚地理解递归。保持这一切。以一个简单的递归为例,开始研究它。以一个因子为例。这是一个不好的例子,但很容易理解。

自上而下的MergeSort

查看我的代码,它简单易用。同样,在您第一次尝试时,两者都不容易理解。在尝试理解这些事情之前,您必须与递归联系。一切都很好。

public class MergeSort 
{
    private int low;
    private int high;
    private int mid;
    public static int[] a;

    public MergeSort(int x)
    {
        a = new int[x];
        a[0]=19;
        a[1]=10;
        a[2]=0;
        a[3]=220;
        a[4]=80;
        a[5]=2000;
        a[6]=56001;
        a[7]=2;

    }

    public void division(int[] a)
    {
        low=0;
        int p;
        high = a.length;
        mid = (high+low)/2;
        if(a.length<2) /*Remember this is the base case*/
        {
            return;
        }
        else
        {
            int[] l = new int[mid];
            int[] r = new int[high-mid];
            /*copying elements from a into l and r*/
            for(p=0;p<mid;p++)
                l[p]=a[p];
            for(int q=0;q<high-mid;q++, p++)
                r[q]=a[p];
            /*first recursive call starts from here*/
            division(l);
            division(r); 
            sortMerge(a, l, r);
        }
    }

    public void sortMerge(int[] a, int[] l, int[] r)
    {

        int i=0, j=0, k=0;
        /*sorting and then merging recursively*/
        while(i<l.length && j<r.length)
            {
                if(l[i]<r[j])
                    {
                        a[k] = l[i]; /*copying sorted elements into a*/ 
                        i++;
                        k++;
                    }
                else
                    {
                        a[k] = r[j];
                        j++;
                        k++;
                    }
            }

        /*copying remaining elements into a*/
        while(i<l.length)
            {
                a[k] = l[i];
                i++;
                k++;
            }

        while(j<r.length)
            {
                a[k] = r[j];
                j++;
                k++;
            }

    }
    /*method display elements in an array*/
    public void display()
    {
        for(int newIndex=0;newIndex<a.length;newIndex++)
        {
        System.out.println(a[newIndex]);
        }
    }


    public static void main(String[] args) 
    {
        MergeSort obj = new MergeSort(8);
        obj.division(a);
        obj.display();
    }

}

答案 1 :(得分:0)

Emz指出:这是由于范围原因。局部变量是一个新对象。 [

  

局部变量由局部变量声明语句声明   (§14.4)。

     

每当控制流进入一个区块(第14.2节)或语句时   (§14.14),为声明的每个局部变量创建一个新变量   在一个局部变量声明语句中立即包含在   阻止或声明。

     

局部变量声明语句可能包含一个表达式   初始化变量。具有初始化的局部变量   但是,表达式未初始化,直到局部变量   声明它被执行的声明语句。 (规则)   明确赋值(§16)阻止局部变量的值   在初始化或以其他方式分配之前使用   值。)当局部变量有效地不再存在   块或for语句的执行已完成。] 1

答案 2 :(得分:0)

以下是合并排序的替代实现,这是bottom-up MergeSort

public class MergeSort {
public static void merge(int[]a,int[] aux, int f, int m, int l) {

    for (int k = f; k <= l; k++) {
        aux[k] = a[k];
    }

    int i = f, j = m+1;
    for (int k = f; k <= l; k++) {
        if(i>m) a[k]=aux[j++];
        else if (j>l) a[k]=aux[i++];
        else if(aux[j] > aux[i]) a[k]=aux[j++];
        else a[k]=aux[i++];
    }       
}
public static void sort(int[]a,int[] aux, int f, int l) {
    if (l<=f) return;
    int m = f + (l-f)/2;
    sort(a, aux, f, m);
    sort(a, aux, m+1, l);
    merge(a, aux, f, m, l);
}
public static int[] sort(int[]a) {
    int[] aux = new int[a.length];
    sort(a, aux, 0, a.length-1);
    return a;
}
}