有人可以解释递归时如何找到所有子集
Can someone explain how recursion works when finding all subsets?
我一生,图片递归及其在做什么。我为此苦苦挣扎。从竞争激烈的程序员手册中,我在C 中发现了以下代码段作为解决以下问题的解决方案:
考虑生成一组N元素的所有子集的问题。 例如,{0,1,2}的子集为;,{0},{1},{2},{0,1}, {0,2},{1,2}和{0,1,2}。
浏览集合所有子集的一种优雅方法是使用递归。 以下功能搜索生成集合的子集 {0,1,...,n -1}。该函数维护一个向量子集,该子集将 包含每个子集的元素。搜索开始时 使用参数0。
调用函数使用参数k调用函数搜索时,它决定 是否将元素k包含在子集中 情况,然后用参数k 1自称,但是,如果k = n, 函数注意到所有元素都已处理过和一个子集 已经生成。
void search(int k) {
if (k == n) {
// process subset
} else {
search(k+1);
subset.push_back(k);
search(k+1);
subset.pop_back();
}
}
可以肯定的是,此功能有效,我手工完成了大约3次,以确保它确实可以完美无缺。但是为什么?
缺乏记住所有递归解决方案的所有问题,我将永远无法提出这种解决方案。这里正在制作什么样的抽象?这里使用的更通用的概念是什么?
我一直在递归中挣扎,因此对任何帮助都得到赞赏。谢谢。
对于每个 k<n 我们只是递归地调用search(k+1)
。一旦使用值 k 在您的集合内,并且没有它。
search(k+1); // call search (k+1) with k NOT inside the set
subset.push_back(k); // puts the value k inside the set
search(k+1); // call search (k+1) with k inside the set
subset.pop_back(); // removes the value k from the set
我们到达 n == k 递归终止。
想象一个深度N的二进制树,每个级别代表当前值和两个分支,该值是否进入您的最终集合。叶子代表所有最终组。
so给定 n = 3 ,并以 k = 0 开始:
search(0);
-> search(1); // with 0 in
->-> search(2); // with 0 in AND 1 in
->->-> search (3); // with 0 in AND 1 in AND 2 in. terminates with (0,1,2)
->->-> search (3); // with 0 in AND 1 in AND 2 not in. terminates with (0,1)
->-> search(2); // with 0 in AND 1 not in
->->-> search (3); // with 0 in AND 1 not in AND 2 in. terminates with (0,2)
->->-> search (3); // with 0 in AND 1 not in AND 2 not in. terminates with (0)
-> search(1); // with 0 not in
->-> search(2); // with 0 not in AND 1 in
->->-> search (3); // with 0 not in AND 1 in AND 2 in. terminates with (1,2)
->->-> search (3); // with 0 not in AND 1 in AND 2 not in. terminates with (1)
->-> search(2); // with 0 not in AND 1 not in
->->-> search (3); // with 0 not in AND 1 not in AND 2 in. terminates with (2)
->->-> search (3); // with 0 not in AND 1 not in AND 2 not in. terminates with ()
AS John 在他的评论中巧妙地指出,递归使用以下事实:
all_subsets(a1,a2,...,an(== all_subsets(a2,...,...,an( u 是设置的联合操作员。
许多其他数学定义将自然地转化为递归调用。
我认为您缺少的是可视化。因此,我建议您访问angorithm-visualizer.org,pythontutor.com等网站。
您可以在此处粘贴此代码片段,然后按行运行它,以便您了解代码流的工作原理。
#include <bits/stdc++.h>
using namespace std;
void subsetsUtil(vector<int>& A, vector<vector<int> >& res, vector<int>& subset, int index) {
res.push_back(subset);
for (int i = index; i < A.size(); i++) {
subset.push_back(A[i]);
subsetsUtil(A, res, subset, i + 1);
}
return;
}
vector<vector<int> > subsets(vector<int>& A) {
vector<int> subset;
vector<vector<int> > res;
int index = 0;
subsetsUtil(A, res, subset, index);
return res;
}
int32_t main() {
vector<int> array = { 1, 2, 3 };
vector<vector<int> > res = subsets(array);
for (int i = 0; i < res.size(); i++) {
for (int j = 0; j < res[i].size(); j++)
cout << res[i][j] << " ";
cout << endl;
}
return 0;
}
您真的很想学习。这将有助于您进行竞争性编程。希望这对您有帮助
这不仅是您的问题。每个开始学习递归的人,他/她都会面对这一点。最主要的只是可视化。从字面上看,这很艰难。
如果您尝试通过方便(使用笔和纸(来可视化任何递归代码,则只会看到"哦!,它正在工作"。但是您应该知道,大多数递归都有复发关系。基于此,该函数复发。同样,要查找特定集合的所有子集,有一个复发关系。这是以下...
通过不服用该项目
来服用特定项目在您的代码中,"采用特定项目"意味着" push_back"answers"不使用特定项目"表示" pop_back"。就是这样。
可能性之一是,不采用任何物品。我们称其为 null Set 。另一种可能性是拿所有物品。这里{0,1,2}。
根据置换组合理论,我们可以计算子集的数量。那就是2 n ,其中n是项目数。这里n = 3。因此,子集的数量将为2 3 = 8。
为0,取它或扔掉,可能性= 2
对于1,取它或扔掉,可能性= 2
对于2,拿或扔掉,可能性= 2
因此,子集的总数为2*2*2 = 8(包括 null Set (。
如果您丢弃 null Set ,那么子集的总数将为8-1 =7。
这是您的递归代码背后的理论。
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 为什么野牛仍在使用"int yylex(void)",却找不到"int yylex(YYS
- C++ Windows 驱动程序MSB3030无法复制该文件,因为它找不到
- 如何找出GDB的SIGTRAP核心转储的根本原因
- 奇怪的(对我来说)返回声明 - 在谷歌上找不到任何关于它的信息
- 函数何时会在c++中包含stack_Unwind_Resume调用
- 找不到QtResource文件中的文件
- Python中的for循环与C++有何不同
- 给定一个向量,如何找到该向量的所有子集和的原始索引
- VC++本机单元测试,找不到调试符号
- RegGetValue在当前用户下找不到名称
- 带有 -stdlib=libc++ 的 clang++ 9.0.1 找不到<optional>
- c++找不到具有相同哈希的无序集合元素
- 找不到以下加速库:boost_fiber
- 找不到 FLTK(缺少:FLTK_INCLUDE_DIR)
- 设置 Visual Studio for MPI: 找不到标识符错误
- "assimp/config.h"找不到,但它在文件夹中
- 链接器找不到在虚拟类 c++ 中访问的静态字段的符号
- 找出向量中所有值之间的相似距离,并将其子集化