我已经与算法脱节了一段时间,并且最近开始修改我的概念。令我惊讶的是,最后我记得我的递归技巧是我很擅长但不再了。所以,我有一个基本的问题,你们这让我很困惑。请先看下面的代码..
private void mergesort(int low, int high) {
if (low < high) {
int middle = (low + high)/2 ;
System.out .println ("Before the 1st Call");
mergesort(low, middle);
System.out .println ("After the 1st Call");
mergesort(middle+1, high);
System.out .println ("After the 2nd Call");
merge(low, middle, high);
}
}
函数调用
mergesort(0,7);
输出
在第一次通话之前
在第一次通话之前
在第一次通话之前
第一次通话后
第二次电话会议后
第一次通话后
在第一次通话之前
第一次通话后
第二次电话会议后
第二次电话会议后
第一次通话后
在第一次通话之前
在第一次通话之前
第一次通话后
第二次电话会议后
第一次通话后
在第一次通话之前
第一次通话后
第二次电话会议后
第二次电话会议后
第二次电话会议后
令我困惑的是上面的代码和结果是第二次递归调用。我理解直到第四个输出线的流程(即:第一次呼叫后)。但我无法理解为什么它(在第一次通话后)输出(第二次通话后)。根据代码的理解,在输出之后(第一次调用之后)应该调用带参数(中间+ 1,高)的mergesort函数,它应该输出(在第一次调用之前)并使用mergesort进入递归调用(低,中)。我熟悉一个递归调用函数并理解并与foreg fibonacci示例同步。
答案 0 :(得分:17)
在第四个输出行,您已从第一个调用和随后的2个递归调用返回,因此现在控件到达System.out .println ("After the 1st Call");
因此,在第二次递归调用之后,条件low < high
为false,因此您只需退出该函数。然后,控制在第二次递归调用之后立即返回到该行。
提示强> 我在学习递归时经常做的一件事就是跟踪堆栈深度(例如为此传递参数),然后在输出中根据堆栈深度缩进输出。这有助于您可视化递归链中的位置,并使调试更容易。
因此,您的调试输入可能类似于以下内容:
entered method, low = 0, high = 10
entered method, low = 0, high = 5
entered method, low = 0, high = 2
exiting method, low = 0, high = 2
exiting method, low = 0, high = 5
exiting method, low = 0, high = 10
答案 1 :(得分:5)
按照执行......
First call 0,7 --> enters if, middle = 3 (integer division), calls again as (0,3)
Second call 0,3 --> enters if, middle = 1, calls again as (0,1)
Third call 0,1 --> enters if, middle = 0, calls again as (0,0)
Fourth call 0,0 --> does not enter if, back to third call
Third call 0,1 --> calls as middle+1,high which is (1,1)
Fifth call 1,1 --> does not enter if, back to third call
Third call 0,1 --> calls the string you didn't expect
可以继续,但这是你不期望的字符串被执行的地方。
答案 2 :(得分:2)
您也可以打印high
和low
的值。跟随递归会容易得多。
答案 3 :(得分:1)
尝试打印middle
变量的值。
最佳实践要求您不要在没有任何变量输出的“函数前”样式调试消息中进行编码。
答案 4 :(得分:1)
4行输出低= 0,中间= 0,高= 1所以调用mergesort(中间+ 1,高)不会打印任何内容(1&lt; 1为假)
答案 5 :(得分:1)
以下缩进对应于递归:
mergesort(0, 7)
middle=3
"Before the 1st Call"
mergesort(0, 3)
middle=1
"Before the 1st Call"
mergesort(0, 1)
middle=0
"Before the 1st Call"
mergesort(0, 0)
(0 < 0) is false so return
"After the 1st Call"
mergesort(1, 1)
(1 < 1) is false so return
"After the 2nd Call"
etc ...
答案 6 :(得分:1)
运行这段代码来理解递归。我已经考虑了控制台中的堆栈深度。希望它易于理解!
#include "stdafx.h"
#include <iomanip>
using namespace std;
static int stackdepth=0;
void mergesort(int[],int,int);
void merge(int[],int,int,int);
void space(int);
int main(int argc,char *argv[])
{
int a[8]={5,7,1,4,9,3,2,0};
mergesort(a,0,7);
for(int i=0;i<10;i++)
// cout<<a[i]<<endl;
return 0;
}
void mergesort(int a[],int low,int high)
{
int mid;
if(low<high)
{
mid=(low+high)/2;
space(stackdepth);
cout<<"First Recursion Enter";
cout<<" Low :"<<low<<" Mid :"<<mid<<endl;
stackdepth++;
mergesort(a,low,mid);
stackdepth--;
space(stackdepth);
cout<<"First Recursion Exit";
cout<<" Low :"<<low<<" Mid :"<<mid<<endl;
space(stackdepth);
stackdepth++;
cout<<"Second Recursion Enter";
cout<<" Mid+1 :"<<mid+1<<" High :"<<high<<endl;
mergesort(a,mid+1,high);
stackdepth--;
space(stackdepth);
cout<<"Second Recursion Exit";
cout<<" Low :"<<mid+1<<" High :"<<high<<endl;
space(stackdepth);
cout<<"Merge Low :"<<low<<" Mid :"<<mid<<"High :"<<high<<endl;
merge(a,low,mid,high);
cout<<endl;
space(stackdepth);
cout<<"------------------------------------------------------------------------------------------"<<endl;
}
}
void space(int stackdepth)
{
for(int i=0;i<stackdepth;i++)
cout<<" ";
}
void merge(int a[],int low,int mid,int high)
{
// cout<<endl;
// cout<<"Merging Begins"<<endl;
int b[8];
int i,k,j;
i=low;k=low;j=mid+1;
while(i<=mid && j<=high)
{
if(a[i]<a[j])
{
b[k++]=a[i++];
}
else
{
b[k++]=a[j++];
}
}
while(i<=mid)
b[k++]=a[i++];
while(j<=high)
b[k++]=a[j++];
space(stackdepth);
for(int i=low;i<=high;i++)
{
a[i]=b[i];
cout<<a[i]<<" ";
}
//cout<<"Low :"<<low<<" Mid :"<<mid<<" High :"<<high<<endl;
// cout<<"Merging Ends"<<endl;
// cout<<endl;
}
答案 7 :(得分:0)
Merge Sort使用递归算法创建一个高度为Log N的完整二叉树,N是该树的节点数(这就是为什么效率如此高)。在下一个图像中,您可以逐步查看针对您的案例的此算法的执行流程,以及创建的二叉树(我认为这是理解其工作原理的最佳方式):
Binary tree that is generated using Merge Sort with an array of 8 positions
Merge Sort的作用是将数组递归地分成两半,首先到达最低的一半,直到我们到达一个单一元素,然后从最近到达的最低元素中分离出更高的元素。这就是为什么它每次调用时自己调用两次,以便创建一个完整的二叉树,当我们到达一个单元(带有叶节点)时停止,并且只有当我们有两个(带有父节点)时才合并。在下图中,您可以逐步查看数组是如何递归拆分的:
Step by step division of an array of 8 elements using Merge Sort
答案 8 :(得分:0)
转到eclipse调试工具。按照步骤,您将找到规则双递归。那就是我做的事。