c ++:嵌套for循环的动态数量(无递归)
Posted
技术标签:
【中文标题】c ++:嵌套for循环的动态数量(无递归)【英文标题】:c++ : dynamic number of nested for loops (without recursion) 【发布时间】:2013-09-11 04:58:34 【问题描述】:我正在编写一个遍历 n 位数字的每个排列的代码段。例如,如果 n = 3,我想遍历以下每个元素:
0, 0, 0
...
0, 1, 0
...
1, 0, 0
...
2、3、4
...
9、9、9
使用嵌套的 for 循环很容易编写代码:
for(digit1 0 to 9)
for(digit2 0 to 9)
for(digit3 0 to 9)
但我想将其概括为 n 位数。例如,如果 n = 10,我现在需要 10 个嵌套的 for 循环。
我已经考虑过这一点,并意识到可以使用递归来解决这个问题(深度优先搜索一棵树,每个节点有 10 个子节点,从 0 到 10,并在深度 n 处停止)。但我的目标是高性能,所以我不想因为开销而使用递归。我还有什么其他选择?
【问题讨论】:
我知道您正在寻找高性能,但请仔细阅读,因为答案有一些很好的信息需要考虑。 ***.com/questions/72209/recursion-or-iteration 是什么让你认为使用 for 循环(复杂度 O(10^n))比使用 trie(logn 的一些复杂度)更有效?? 为什么你认为递归很慢?您是否进行了基准测试? 你可以设置一个数字数组(或其他东西),然后像图灵一样上下移动。它是否会比递归快得多还有待观察。 为了记录,您正在通过一组数字,而不是通过排列。排列将类似于 123 213 132 321 312 231 【参考方案1】:如果您想在不使用递归的情况下使用单个循环来模拟嵌套循环,您可以通过为每个循环变量维护一组状态(或槽)来实现,这可以通过数组轻松完成。循环然后变成一个简单的问题,即向该数组“加 1”,根据需要执行进位操作。如果你的嵌套深度是 n,并且每个循环的最大边界是 b,那么这个的运行时间是 O(b^n),因为进位操作只会最多花费你 O(b^n) (我将跳过这里的代数)。
这是工作 C++ 代码(更新以集成 Drew 的评论):
void IterativeNestedLoop(int depth, int max)
// Initialize the slots to hold the current iteration value for each depth
int* slots = (int*)alloca(sizeof(int) * depth);
for (int i = 0; i < depth; i++)
slots[i] = 0;
int index = 0;
while (true)
// TODO: Your inner loop code goes here. You can inspect the values in slots
// Increment
slots[0]++;
// Carry
while (slots[index] == max)
// Overflow, we're done
if (index == depth - 1)
return;
slots[index++] = 0;
slots[index]++;
index = 0;
【讨论】:
请注意,对于第一个slots[index]++
,index
将始终为零,因此您可以使用slots[0]++
。
@David,实际上,长度为 n 的 m 个嵌套循环和长度为 n^m 的单个循环都将具有 O(n^m).... 不需要代数 :)
@DavidAirapetyan 你能帮忙提供一段示例代码来使用这个函数吗?
当然,这是一个完整的例子:gist.github.com/davidair/8cd9e906eeab26083a4a3727001830ff【参考方案2】:
如果您想要特定长度的所有数字的排列;如您展示的 3 位数字示例。不要运行 3 个嵌套循环,而是运行一个 10^3 的循环,这将为您提供所有排列。
如果您想将其用于索引,则将每次迭代中获得的数字拆分为数字。
因此,您将只需要一个循环而不是嵌套循环。
【讨论】:
简单有效。【参考方案3】:在一般情况下,如果您想将递归替换为平面代码,您应该使用堆栈 (LIFO)。所以如果你有递归算法:
void print(std::string str, int depth)
if (depth == n)
std::cout << str << std::endl;
return;
for (int i = 0; i < 10; ++i)
char val[2] = i + '0', 0 ;
print(str + val + ", ", depth+1);
您可以通过保存局部变量(在本例中为 str 和 i)将其转换为基于 LIFO:
struct StackItem
StackItem(const std::string& ss, unsigned ii)
: str(ss), i(ii)
std::string str;
int i;
;
void print_norec()
std::list< StackItem > stack;
stack.push_back(StackItem("", 0));
while (!stack.empty())
StackItem& current = stack.back();
if (stack.size() == n+1)
std::cout << current.str << std::endl;
stack.pop_back(); // return from "recursive" function
continue;
if (current.i < 10)
char val[2] = current.i + '0', 0 ;
// call "recursive" function
stack.push_back(StackItem(current.str + val + ", ", 0));
current.i++;
else
stack.pop_back(); // return from "recursive" function
【讨论】:
以上是关于c ++:嵌套for循环的动态数量(无递归)的主要内容,如果未能解决你的问题,请参考以下文章