我必须编写一个递归方法,该方法遍历链表并返回正数的整数。这是一个问题:
下面的方法countPos
必须是一个带Node
头的递归方法
作为其参数,沿着head为首的列表,并计算具有正数据字段的节点数。
我的代码有效,但我不明白它是如何工作的。
public int countPos(Node head) {
int count = 0;
if (head == null) { return count; }
if (head.data > 0) {
count++;
return count + countPos(head.next);
} else {
return count + countPos(head.next);
}
}
我遇到的问题是,我不知道每次调用该方法时计数如何都不会被设置为0。由于某种原因,下次调用该方法时将忽略语句int count = 0;
。这是因为我还要回归count
吗?任何解释将不胜感激。
感谢。
答案 0 :(得分:3)
不要通过跟踪执行或调试来开始。递归的强大之处在于它可以让你用简单的逻辑来推理复杂的程序。
您的代码是偶然的。它反映了谁写了它(你呢?)并不了解递归如何解决问题。它比必要的复杂得多。
要利用递归,请考虑手头的问题:
完成所有这些后,大多数递归算法的伪代码是:
function foo(args)
if args describe a base case
return the base case answer.
solve the smaller problem or problems by calling foo with
args that describe the smaller problem!
use the smaller problem solution(s) to get the answer for this set of args
return that answer
end
让我们将此应用于您的案例:
问题:计算列表中的正数项目。
int countPos(Node head)
。countPos(head.next)
。把这一切放在一起:
int countPos(Node head) {
// Take care of the base case first.
if (head == null) return 0;
// Solve the smaller problem.
int positiveCountWithoutHead = countPos(head.next);
// Now the logic in step 2. Return either the positive count or 1+ the positive count:
return head.data > 0 ? positiveCountWithoutHead + 1 : positiveCountWithoutHead;
}
你可能通过跟踪这样的事情的执行来学习一点点。但是,试图通过推理堆栈的内容来编写递归代码是一个死胡同。要取得成功,你必须在更高层次上思考。
让我们尝试一下并不完全遵循标准模板:递归二进制搜索。我们有一个整数数组a
,并且如果数组中存在x
,则会尝试查找-1
的索引,如果不存在则返回i0
。
问题:在位置i1-1
和i0
之间搜索数组。
(上面是一个例子,说明你有时必须通过添加参数来解决问题,以便在递归调用或调用中描述较小的子问题。这里我们添加新的参数{{ 1}}和i1
以便我们可以指定a
的子数组。了解如何以及何时执行此操作是一个实践问题。所需的参数可能因语言特征而异。)
int search(int [] a, int x, int i0, int i1)
mid = (i0 + i1) / 2
。然后子问题要么搜索数组的前半部分,要么排除mid
,或者在search(a, x, i0, mid)
和search(a, x, mid + 1, i1)
。i0 >= i1
,则没有要搜索的元素,所以如果我们-1
,则返回a[mid] == x
和2),然后我们就找到了x
并且可以返回mid
。把这一切放在一起
int search(int [] a, int x, int i0, int i1) {
// Take care of one base case.
if (i0 >= i1) return -1;
// Set up mid and take care of the other base case.
int mid = (i0 + i1) / 2;
if (a[mid] == x) return mid;
// Solve one or the other subproblems. They're both smaller!
return x < a[mid] ? search(a, x, i0, mid) : search(a, x, mid + 1, i1);
}
开始搜索:
int search(int [] a, int x) { return search(a, x, 0, a.length); }
答案 1 :(得分:2)
每次拨打countPos()
时,都会启动该功能的新版本。这个函数从一个干净的平板开始,意味着所有的局部变量(count
)都是它自己的,而没有其他的#34; copy&#34; countPos
可以查看或修改其局部变量。
这些&#34;副本之间传递的唯一状态&#34;或countPos
是作为参数传递的变量(Node head
)。
因此,假设列表[1,-2,3]
,这是一个粗略的工作流程countPos
开始,并说正节点的数量等于1,因为&#34; 1&#34;是积极的。无论下一个函数返回什么,正节点的总数等于1 +。head == null
,因此返回0. 现在每个递归函数一个接一个地返回到调用它的原始函数,其中包含正节点的总数&#34;滚雪球&#34;当我们回来时。
最后返回的总数将是2。