C++ 递归:理解(子集和)包含/排除模式
我需要理解这个递归是如何工作的,我理解简单的递归示例,但更高级的示例很难。即使有两行代码我也有问题。。。返回语句本身。我只是对它的工作原理略知一二,尤其是and/or操作符。任何见解都是非常受欢迎的C++ 递归:理解(子集和)包含/排除模式,c++,recursion,subset-sum,C++,Recursion,Subset Sum,我需要理解这个递归是如何工作的,我理解简单的递归示例,但更高级的示例很难。即使有两行代码我也有问题。。。返回语句本身。我只是对它的工作原理略知一二,尤其是and/or操作符。任何见解都是非常受欢迎的 bool subsetSumExists(Set<int> & set, int target) { if (set.isEmpty()) { return target == 0; } else { int
bool subsetSumExists(Set<int> & set, int target) {
if (set.isEmpty()) {
return target == 0;
} else {
int element = set.first();
Set<int> rest = set - element;
return subsetSumExists(rest, target)
|| subsetSumExists(rest, target - element);
}
}
||是逻辑或。它从左到右进行评估并短路
这意味着在表达式A | | B中,首先计算A。如果为真,则整个表达式为真,不进行进一步计算。如果A为false,则对B求值,表达式得到B的值
在您的示例中,A尝试在不使用集合中的第一个元素的情况下获得相同的和。B是使用集合中的第一个元素,它减少了剩余的总和,并尝试与元素的其余部分一起获得该值。要理解递归,需要理解递归。 要做到这一点,你需要反复思考 在这种特殊情况下 对于任何:子集,目标 若集合为空且目标为0,则存在子集合 否则,请删除集合的第一个元素。使用步骤0检查是否存在subdetSumset、target或subdetSumset、target-removed_元素
集合减法看起来是一种奇怪的语法,但我假设它意味着元素上的pop 它通过寻找每一个可能的组合来工作,尽管它是指数型的 在| |语句中,LHS是包括当前元素的和,RHS是不包括当前元素的和。因此,在指数树下,每个元素的每一个组合都会被打开或关闭 顺便说一下,指数意味着如果你有30个元素,它将产生2到30的幂,即0x40000000或接近十亿个组合 当然,你的内存可能会用完
如果找到了解决方案,它可能不会在所有2^N情况下运行。如果没有解决方案,它将始终访问所有这些问题。让我们先看看算法 基本情况,即当集合为空时,递归终止 否则,程序从集合中减去第一个元素 现在它将调用SubsetSumeExistsRest、target并检查其是否为真, 如果是,它将返回true,否则它将调用 subsetsumexistrest,target-element并返回它所返回的任何内容 返回 简单地说,只有当第一个子集subsetsumexistrest,target返回false时,它才会调用subsetsumexistrest,target-element 现在,让我们试着用一个小样本集{3,5}和一个8的和来运行这段代码。从现在起,我将调用函数sSE
sSE({3,5}, 8) => "sSE({5}, 8) || sSE({5},(8-3))"
sSE({5}, 8) => sSE({}, 8) || sSE({}, (8-5))
sSE({}, 8) => false.. now will call sSE({}, (8-5))
sSE({}, 3) => false.. now will call sSE({5}, (8-3))
sSE({5}, 5) => sSE({}, 5} || sSE({}, (5-5))
sSE({}, 5) => false.. now will call sSE({}, (5-5))
sSE({}, 0) => true.. ends here and return true
递归代码通常与归约概念结合在一起。一般来说,约简是通过某种转换将未知问题约简为已知问题的一种方法 让我们看看你的代码。您需要确定是否可以从输入数据集的元素构造给定的目标和。 如果数据集为空,则除了将目标和与0进行比较外,无需其他操作 否则,让我们应用减少。如果我们从集合中选择一个数字,实际上可能有两种可能性-所选数字参与您正在寻找的和,或者不参与。这里没有其他的可能性涵盖所有的可能性是非常重要的!。事实上,选择哪个数据元素并不重要,只要您能够覆盖剩余数据的所有可能性 第一种情况:数字不参与总和。我们可以将问题简化为一个较小的问题,数据集没有被检查的元素,目标和相同 第二种情况:数字参与总和。我们可以将问题简化为一个较小的问题,数据集不包含被检查的元素,请求的和减少了数字的值 请注意,此时您不知道这些情况是否属实。你只需继续减少它们,直到你得到一个微不足道的空案例,你可以肯定地知道答案
如果这两种情况中的任何一种都是真的,那么原始问题的答案将是真的。这正是运算符| |所做的-如果它的任何一个操作数(这两种情况的结果为真),它将产生真值。如果我自己说的话,理解这个问题的困难源于| |运算符。让我们用另一种方式看一下相同代码的底部返回语句
if (subsetSumExists(rest, target - element))
return true;
if (subsetSumExists(rest, target))
return true;
return false;
因此,您在理解递归或布尔运算符和/或两者时遇到困难!例如,和/或如何选择返回哪一个?第一个还是第二个?+1为了理解递归,你需要理解递归!当我阅读理解递归时,我有一种似曾相识的感觉,你需要理解递归。