C++ 更好地理解递归
为了更好地理解递归,我尝试在代码中打印一些输出,以便研究这些步骤C++ 更好地理解递归,c++,recursion,C++,Recursion,为了更好地理解递归,我尝试在代码中打印一些输出,以便研究这些步骤 #include <tuple> #include <string> #include <iostream> #include <map> #include "print.h" std::tuple<int, int, int> find_max_crossing_subarray(int A[], int low, int mid, int high) { in
#include <tuple>
#include <string>
#include <iostream>
#include <map>
#include "print.h"
std::tuple<int, int, int> find_max_crossing_subarray(int A[], int low, int mid, int high)
{
int max_left, max_right;
int left_sum = std::numeric_limits<int>::min();
int sum = 0;
for(int i = mid; i >= low; i--) {
sum += A[i];
if(sum > left_sum) {
left_sum = sum;
max_left = i;
}
}
int right_sum = std::numeric_limits<int>::min();
sum = 0;
for(int j = mid + 1; j <= high; j++) {
sum += A[j];
if(sum > right_sum) {
right_sum = sum;
max_right = j;
}
}
return std::make_tuple(max_left, max_right, left_sum + right_sum);
}
std::tuple<int, int, int> find_max_subarray(int A[], int low, int high)
{
if(high == low) {
return std::make_tuple(low, high, A[low]);
}
else {
int mid = (high + low) / 2;
std::tuple<int, int, int> left(find_max_subarray(A, low, mid));
std::cout << "left: ";
print(left);
int left_low, left_high, left_sum;
std::tie(left_low, left_high, left_sum) = left;
std::tuple<int, int, int> right(find_max_subarray(A, mid + 1, high));
std::cout << "right: ";
print(right);
int right_low, right_high, right_sum;
std::tie(right_low, right_high, right_sum) = right;
std::tuple<int, int, int> cross(find_max_crossing_subarray(A, low, mid, high));
std::cout << "cross: ";
print(cross);
int cross_low, cross_high, cross_sum;
std::tie(cross_low, cross_high, cross_sum) = cross;
if(left_sum >= right_sum && left_sum >= cross_sum) {
return left;
}
else if(right_sum >= left_sum && right_sum >= cross_sum) {
return right;
}
else {
return cross;
}
}
}
int main()
{
int arr_3[3] = {-3, 2, 3};
int arr_4[4] = {5, -23, 1, 44};
int arr_6[6] = {5, -23, 1, 44, -2, 5};
int arr[16] = {-23, 3, 9 ,7, -12, 87, -25, 2, 3, 5, 32, -8, 6, -82, 3, 9};
print(arr_4, 4);
std::tuple<int, int, int> maple(find_max_subarray(arr_4, 0, 3));
print(maple);
return 0;
}
我理解输出的前三行(即左、右、交叉的起始位置)。但我不明白第四行和第四行以外的内容是从哪里来的。我试着追溯函数,我一直在想我应该在交叉:01-18
之后的第四行输出中得到左:11-23
编辑:
我应该指出,在左:2 1
之后,虽然很难想象,但我还是有些理解。递归已经结束,代码只是反向级联
第二次编辑:
我猜在第四行发生的事情是,第一个find\u max\u子数组
正在完成,它将返回函数代码中的第一个if
语句。现在,它正在移动到第二个查找\u max\u子阵列
第三次编辑:
我想我的困惑在于,代码不是向后级联的,而是在递归结束后返回到第一个调用
第四次编辑:
当我去六个元素的时候,虽然它看起来并不是简单地返回到第一个调用
5 -23 1 44 -2 5
left: 0 0 5
right: 1 1 -23
cross: 0 1 -18
left: 0 0 5
right: 2 2 1
cross: 0 2 -17
left: 0 0 5
left: 3 3 44
right: 4 4 -2
cross: 3 4 42
left: 3 3 44
right: 5 5 5
cross: 3 5 47
right: 3 5 47
cross: 2 5 48
2 5 48
我的意思是,我猜这是因为子数组有三个元素,而不是两个。所以有两对,而不是一对。当你认为这是理所当然的,但看不见它的时候,这是有道理的
上次编辑:
所以当我到8点时,它是成对的。前两个元素,然后返回原始调用。接下两对,然后回电话。我不太清楚为什么在这种奇怪的情况下,它会在第一对和第二对以及第一对和第三对都完成之前不回电话
5 -23 1 44 -2 5 6 -3
left: 0 0 5
right: 1 1 -23
cross: 0 1 -18
left: 0 0 5
left: 2 2 1
right: 3 3 44
cross: 2 3 45
right: 2 3 45
cross: 0 3 27
left: 2 3 45
left: 4 4 -2
right: 5 5 5
cross: 4 5 3
left: 5 5 5
left: 6 6 6
right: 7 7 -3
cross: 6 7 3
right: 6 6 6
cross: 5 6 11
right: 5 6 11
cross: 2 6 54
2 6 54
解决的问题:
我在理解递归时遇到的问题是,对于每个递归步骤,我都使用原始的
high
值。事实上,我用正确的高值
将其分块写在纸上,所有内容都集中在一起。正如上次编辑后在我的问题解决部分所述,我意识到在我的分析中,我对高值
使用了错误的值。我没有看到这一点,因为虽然我使用的是块,但我使用的是序列块,而不是块块
我为每个子块逐块更新了high
。我把插图贴在下面。这与我得到的结果一致。return
语句伴随着每个块
四要素案例:
(0,3)
(0,1)
(0,0) -> left
(1,1) -> right
-> cross
return left
(2,3)
(2,2) -> left
(3,3) -> right
-> cross
return right
return cross
(0,4)
(0,2)
(0,1)
(0,0) -> left
(1,1) -> right
-> cross
return left
(2,2) -> right
-> cross
return left
(3,4)
(3,3) -> left
(4,4) -> right
-> cross
return right
return cross
五要素案例:
(0,3)
(0,1)
(0,0) -> left
(1,1) -> right
-> cross
return left
(2,3)
(2,2) -> left
(3,3) -> right
-> cross
return right
return cross
(0,4)
(0,2)
(0,1)
(0,0) -> left
(1,1) -> right
-> cross
return left
(2,2) -> right
-> cross
return left
(3,4)
(3,3) -> left
(4,4) -> right
-> cross
return right
return cross
如上所述,在上次编辑后的问题解决部分中,我意识到在我的分析中,我使用了错误的
高值
。我没有看到这一点,因为虽然我使用的是块,但我使用的是序列块,而不是块块
我为每个子块逐块更新了high
。我把插图贴在下面。这与我得到的结果一致。return
语句伴随着每个块
四要素案例:
(0,3)
(0,1)
(0,0) -> left
(1,1) -> right
-> cross
return left
(2,3)
(2,2) -> left
(3,3) -> right
-> cross
return right
return cross
(0,4)
(0,2)
(0,1)
(0,0) -> left
(1,1) -> right
-> cross
return left
(2,2) -> right
-> cross
return left
(3,4)
(3,3) -> left
(4,4) -> right
-> cross
return right
return cross
五要素案例:
(0,3)
(0,1)
(0,0) -> left
(1,1) -> right
-> cross
return left
(2,3)
(2,2) -> left
(3,3) -> right
-> cross
return right
return cross
(0,4)
(0,2)
(0,1)
(0,0) -> left
(1,1) -> right
-> cross
return left
(2,2) -> right
-> cross
return left
(3,4)
(3,3) -> left
(4,4) -> right
-> cross
return right
return cross
可能重复。附加调试器并单步执行代码将非常有帮助。如何附加调试器?@OliCharlesworth。你的链接指向了这个问题。@OliCharlesworth我必须承认我得到了:D我点击了它,就像。。。wtf发生在这里d可能重复。附加调试器并单步执行代码将非常有帮助。如何附加调试器?@OliCharlesworth。你的链接指向了这个问题。@OliCharlesworth我必须承认我得到了:D我点击了它,就像。。。wtf发生在这里D