这是关于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。
答案 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),这确实太多了。因此,人类必须找到更好的解决方案。它是人类的需要,非常重要。我知道它很烦人,我已经经历了这种无意识的。
请在尝试之前对递归进行一些研究。清楚地理解递归。保持这一切。以一个简单的递归为例,开始研究它。以一个因子为例。这是一个不好的例子,但很容易理解。
查看我的代码,它简单易用。同样,在您第一次尝试时,两者都不容易理解。在尝试理解这些事情之前,您必须与递归联系。一切都很好。
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;
}
}