我有一棵树(代表一个SalesPath),每个节点都有成本。
对象用于计算最小的SalesPath,即每个节点的成本之和 从根节点到叶节点
下面的代码使用递归来解决问题,代码工作正常 (在显示的树中,SalesPath(0-3-2-1-1)的最便宜路径= 7)
我在查看堆栈时遇到困难,无法清楚地说明/解释递归如何跟踪最便宜的成本 (即int最便宜= cheapestCost + rootNode.cost)在多个分支之间
例如从0-5-4,最便宜的费用是9 而从0-3 -2 -1 -1,最便宜的费用是7
代码:
static class SalesPathRecursion{
static int getCheapestCost_Recursion(Node rootNode){
int cheapestCost = Integer.MAX_VALUE;
Node[] children = rootNode.children;
int tempCost =0;
if(children == null){
System.out.println(" Children == null, returning rootNode.cost => " + rootNode.cost);
return rootNode.cost;
}else{
for(int i=0; i< children.length; i++){
tempCost = getCheapestCost_Recursion(children[i]);
if(tempCost < cheapestCost){
cheapestCost = tempCost;
}
System.out.println(" CheapestCost is " + cheapestCost);
}
}
int cheapest = cheapestCost + rootNode.cost;
System.out.println(" Returning : rootNode.cost => " + rootNode.cost + " cheapest is => " + cheapest);
return cheapest;
}
}
答案 0 :(得分:0)
这是递归的经典示例!
调用方调用递归函数,传入根节点并询问“叶子的最便宜的价格是多少?”。调用树底部的根节点(0)响应:“我不确定。请稍等,让我的每个孩子看看哪个孩子的成本最低”。但是,还没有一个孩子对这个问题有任何答案,因此他们向每个孩子询问完全相同的问题,依此类推。
最终,到达leaf node(例如,您的示例中为4),并说:“我知道!从我到叶节点的最便宜的费用是我自己的价值,4我要告诉父母。”这称为base case。基本情况是迄今为止的第一个函数调用,它提供了一个非常小的子问题的明确答案,在此情况下,该信息将用于构建更大问题的解决方案。将太大而无法立即解决的问题分解为容易解决的小问题的过程称为divide and conquer。
节点4的父节点5现在知道从其自身到叶子(4,它的唯一子节点)的最便宜的成本是5 + 4 = 9
,并告诉其父节点根节点0。根节点是现在,它从其最左边的子级获得了确定的值(从根到叶的路径成本为9,比无穷大,因此它是迄今为止存储的最好的),但仍然需要询问其他子项的成本,是的。最终,所有孩子都会报告各自的费用,其中0->3->2->1->1
证明是最便宜的。
该算法使用depth-first search,先探索一个分支,然后再探索其他任何分支。换句话说,0->5->4
在0->3->2->1->1
之前已被完全研究。
考虑一个具有独特成本的小型示例树:
0
/ \
4 1
/
5
我们希望0->1
是成本为1的最便宜的路径。让我们在该树上使用详细的会话输出来运行该算法。每当进行递归调用时,打印都会缩进。括号是指特定的节点。查看是否可以跟踪执行情况:
(0), what's your min cost?
(0) says: Hang on, I need to ask my children...
(0) says: I'm asking (4) for its min cost...
(4), what's your min cost?
(4) says: Hang on, I need to ask my children...
(4) says: I'm asking (5) for its min cost...
(5), what's your min cost?
(5) says: I'm a leaf! My min cost is 5
(4) says: I got the cost 5 from (5), a new best!
(4) says: I checked my children and I know my min cost is 9
(0) says: I got the cost 9 from (4), a new best!
(0) says: I'm asking (1) for its min cost...
(1), what's your min cost?
(1) says: I'm a leaf! My min cost is 1
(0) says: I got the cost 1 from (1), a new best!
(0) says: I checked my children and I know my min cost is 1
这是另一棵更大的树,再次具有唯一的节点:
0
/ | \
4 1 7
/ / \
5 6 2
\
3
我们希望0->1->2->3
是成本为6的最便宜的路径。让我们看一下详细的输出。再试一次以跟踪执行情况。
(0), what's your min cost?
(0) says: Hang on, I need to ask my children...
(0) says: I'm asking (4) for its min cost...
(4), what's your min cost?
(4) says: Hang on, I need to ask my children...
(4) says: I'm asking (5) for its min cost...
(5), what's your min cost?
(5) says: I'm a leaf! My min cost is 5
(4) says: I got the cost 5 from (5), a new best!
(4) says: I checked my children and I know my min cost is 9
(0) says: I got the cost 9 from (4), a new best!
(0) says: I'm asking (1) for its min cost...
(1), what's your min cost?
(1) says: Hang on, I need to ask my children...
(1) says: I'm asking (6) for its min cost...
(6), what's your min cost?
(6) says: I'm a leaf! My min cost is 6
(1) says: I got the cost 6 from (6), a new best!
(1) says: I'm asking (2) for its min cost...
(2), what's your min cost?
(2) says: Hang on, I need to ask my children...
(2) says: I'm asking (3) for its min cost...
(3), what's your min cost?
(3) says: I'm a leaf! My min cost is 3
(2) says: I got the cost 3 from (3), a new best!
(2) says: I checked my children and I know my min cost is 5
(1) says: I got the cost 5 from (2), a new best!
(1) says: I checked my children and I know my min cost is 6
(0) says: I got the cost 6 from (1), a new best!
(0) says: I'm asking (7) for its min cost...
(7), what's your min cost?
(7) says: I'm a leaf! My min cost is 7
(0) says: I got the cost 7 from (7) but it's not the best
(0) says: I checked my children and I know my min cost is 6
以下是产生以上输出的代码:
static void say(String message, int depth) {
for (int i = 0; i < depth; i++) {
System.out.print(" ");
}
System.out.println(message);
}
static int getCheapestCostRecursion(Node node, int depth) {
say("(" + node.cost + "), what's your min cost?", depth);
if (node.children.length == 0) {
say(
"(" + node.cost +
") says: I'm a leaf! My min cost is " +
node.cost, depth
);
return node.cost;
}
say(
"(" + node.cost +
") says: Hang on, I need to ask my children...",
depth
);
int cheapestCost = Integer.MAX_VALUE;
for (Node child : node.children) {
say(
"(" + node.cost +
") says: I'm asking (" + child.cost +
") for its min cost...", depth
);
int childCost = getCheapestCostRecursion(child, depth + 6);
say(
"(" + node.cost +
") says: I got the cost " + childCost +
" from (" + child.cost + ")", depth
);
if (childCost < cheapestCost) {
say(
"(" + node.cost +
") says: I got the cost " + childCost +
" from (" + child.cost + "), a new best",
depth
);
cheapestCost = childCost;
}
else {
say(
"(" + node.cost +
") says: I got the cost " + childCost +
" from (" + child.cost +
"), but it's not the best", depth
);
}
}
say(
"(" + node.cost +
") says: I checked my children and I know " +
"my min cost is " + (cheapestCost + node.cost),
depth
);
return cheapestCost + node.cost;
}