如何使用循环编写此递归

How to write this recursion with loops

本文关键字:递归 何使用 循环      更新时间:2023-10-16

我在一个网站上看到了以下练习。它基本上说,在不使用递归和向量、堆栈等结构的情况下编写以下函数:

void rec(int n) {
if (n != 0) {
cout << n << " ";
rec(n-1);
rec(n-1);
}
}

起初我以为这会很容易,但令人惊讶的是,我正在努力实现它

为了更好地理解它,我将其定义为如下数学函数:

f(x(={1,如果x=0,f(x-1(+f(x-2(,否则}(其中+运算符表示串联,-是正常的减号(

然而,展开这件事让它变得更难了,我陷入了困境。有什么直接的方法可以把它写成一个循环吗?而且,更普遍地说,有没有一种算法可以解决这类问题?

如果你对它进行了足够的处理,你至少可以获得一种输出有序序列的方法,而无需重新访问:(

let n = 5
// Recursive 
let rec_str = ''
function rec(n) { 
if (n != 0) { 
rec_str += n
rec(n-1); 
rec(n-1); 
} 
}
rec(n)
console.log(rec_str)
// Iterative 
function f(n){
let str = ''

for (let i=1; i<1<<n; i++){
let t = i
let p = n
let k = (1 << n) - 1
while (k > 2){
if (t < 2){
break 
} else if (t <= k){
t = t - 1
p = p - 1
k = k >> 1
} else {
t = t - k
}
}
str += p
}
console.log(str)
}
f(n)

(代码正在构建一个字符串,我认为根据规则应该不允许这样做,但仅用于演示;我们可以只输出数字。(


void loop(int n)
{
int j = 0;
int m = n - 1;
for (int i = 0; i < int(pow(2, n)) - 1; i++)
{
j = i;
if (j == 0)
{
std::cout << n << " ";
continue;
}
m = n - 1;
while (true)
{
if (m == 1)
{
std::cout << m << " ";
m = n - 1;
break;
}
if (j >= int(pow(2, m)))
{
j = j - int(pow(2, m)) + 1;
}
if (j == 1)
{
std::cout << m << " ";
m = n - 1;
break;
}
else
{
j--;
}
m--;
}
}
std::cout << std::endl;
}

对于n=3,例如

out =     [3 2 1 1 2 1 1] 
indexes = [0 1 2 3 4 5 6] 

考虑索引列表;对于i>0和i<=2^(m(索引i的值与索引i+2^(m(-1的值相同,其中m=n-1。每一个n都是如此。如果你在列表的后半部分,那么用这个公式在前半部分找到它的对应索引。如果得到的数字是1,则值为m。如果不是,则表示您处于树的较低级别。m=m-1并重复,直到索引为1或m=1,在这种情况下,您已经到达树的末尾,打印1。

例如,当n=4时,这就是所有索引在每个while步骤中发生的情况。p(x(表示在该索引处打印出值x。A/表示索引已打印。:

n = 4,m = 3
[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14]
m = 3
[p(n=4) 1 2 3 4 5 6 7 8 9 10 11 12 13 14]
if(i >=2^3) -> i = i -2^3 + 1)
[/ 1 2 3 4 5 6 7 1 2 3 4 5 6 7]
if(i == 1) -> print m, else i = i -1
[/ p(3) 1 2 3 4 5 6 p(3)1 2 3 4 5 6]
m = 2
if (i >=2^2) -> i = i - 2^2 +1
[/ / 1 2 3 1 2 3 / 1 2 3 1 2 3] 
if(i == 1) -> print m, else i = i -1
[ / / p(2) 1 2 p(2) 1 2 / p(2) 1 2 p(2) 1 2]
m = 1
if (m == 1) -> print(m)
[ / / / p(1) p(1) / p(1) p(1) / / p(1) p(1) / p(1) p(1)]

因此,结果是:

[4 3 2 1 1 2 1 1 3 2 1 1 2 1 1]
void via_loop(int n) {
string prev = "1 ", ans = "1 ";
for (int i = 2; i <= n; i++) {
ans = to_string(i) + " " + prev + prev;
prev = ans;
}
cout << ans;
}

想法是保存之前计算每个数字的结果。完整代码:

void rec(int n) {
if (n != 0) {
cout << n << " ";
rec(n-1);
rec(n-1);
}
}
void via_loop(int n) {
string prev = "1 ", ans = "1 ";
for (int i = 2; i <= n; i++) {
ans = to_string(i) + " " + prev + prev;
prev = ans;
}
cout << ans;
}
int main() {
int n = 5;
cout << "Rec : ";
rec(n);
cout << endl;
cout << "Loop: ";
via_loop(n);
cout << endl;
}

输出:

Rec : 5 4 3 2 1 1 2 1 1 3 2 1 1 2 1 1 4 3 2 1 1 2 1 1 3 2 1 1 2 1 1
Loop: 5 4 3 2 1 1 2 1 1 3 2 1 1 2 1 1 4 3 2 1 1 2 1 1 3 2 1 1 2 1 1