关于递归的一些思考

关于递归的一些思考:


起因是学弟看不懂多层递归了,需要帮他理清一下,当前写的也是挺乱的,故作为1.0版本,之后想到更好的表述再更新。
我不是个太会表达的人,所以说的不好,但是,自学的时候,我认为,对一个需要学习或者练习的东西能够形成图会好点。如果表述不清,就绘成图吧。。。

递归:调用自己

  • 这个定义是从运行状态来定义的。

仅从做的事情的角度看下递归:

  • 所有做的事情的步骤都是一样的。
  • 有个初始步骤,这样可以有个出口
  • 从这里看的话,我们往往建模都会向数列方向去靠。
    • 数列有一个初始值
    • 数列有个针对于 An -> An+1的一个关系表达式
  • 遍历看起来也是这样,里面做的事情的步骤是一样的,有一个初始步骤
  • 所以,如果从做事的角度来看的话,遍历和递归是一样的。

关于递归思考转换成代码

  • 如果当前已经建模成最简单的数学表达式。诸如递推,斐波那契之类的。直接就能成为代码
  • 如果是稍微复杂点的步骤,看到学弟已经晕了,这时候一定要分而治之,找到每次做事情不变的地方
    • 最简单直观的 ,相对于当前这一件事情不变的, 如果是for循环,就是那个i
    • 如果是递归,那就是那个栈是不变的,我们去看怎么返回的,就能知道哪个往往是不变的。

小栗子:

输出某个自然数之前的所有排列顺序。
诸如N = 1, 输出: 1
N = 2, 输出: 1 2; 2 1
N = 3, 输出: 1 2 3; 1 3 2; 213; 231; 312; 321;

分析
  • 对于上述例子,我们很容易想到最简单的高中排列组合学到的排列。

回想下:当时我们学习排列的时候怎么学习的? 我当时学习的是:有一堆小球在地上,小球有编号,
这边有槽,我们把球放到槽里,有多少种放的方式?

当时并没有学公式,只是自己依次试出来,然后统计。
尝试的步骤:

  • 步骤 1:把一个球 拿过来,放到左边第一个槽,(一般都会拿编号1的球,至于为什么放左边,我是左撇子)
  • 重复步骤1:放到下一个槽,直到放完
  • 写出这个排列
  • 我一般从最尾巴交换两个球。
  • 写出这个排列

但是从另一种角度去看:

  • 我们只看槽
  • 对于 当前槽 来说,每次动作:
  • 从剩下的球中,挑选一个球, 然后放到槽里
  • 然后进入下一个槽。
  • 然后拿出这个球
  • 重复上面的操作

这样看的好处是,横向看而不是顺序看,每个槽都遍历了这些球。

int ball = 50;    //假设球有50个
int flag[50];     //设置50个更好理解点
int slot[100];    //放置的槽
//一次槽的放置球
void SetBall(int OneSlot)
{
  for (size_t i = 0; i < ball; i++) {
    // 如果当前这个球没有被使用,则放到槽里
    if (flag[i] == 0) {     
      flag[i] = 1;              //我们使用了这个球    
      slot[OneSlot] = i + 1;    //把这个球放到槽里
    }
  }
}
int ball = 50;    //假设球有50个
int flag[50];     //设置50个更好理解点
int slot[100];    //放置的槽
//放置到下一个槽
void SetBall(int OneSlot)
{
  for (size_t i = 0; i < ball; i++) {
    // 如果当前这个球没有被使用,则放到槽里
    if (flag[i] == 0) {     
      flag[i] = 1;              //我们使用了这个球    
      slot[OneSlot] = i + 1;    //把这个球放到槽里

      SetBall(OneSlot + 1);     //这里放置到了下一个槽
      flag[i] = 0;              //拿出球
    }
  }
}

开始确定输出:

//从槽的观点去写
int flag[50];
int slot[100];
int ball = 50;


void SetBall(int OneSlot) {
  if (OneSlot == ball) {
    //print array of slot
  }
  else
  {
    for (size_t i = 0; i < ball; i++) {
       if (flag[i] == 0) {
         flag[i] = 1;
         slot[OneSlot] = i + 1;

         SetBall(OneSlot);
         flag[i] = 0;       
       }
    }
  }
}

假设 字符串 “abcdefg\0”

步骤:

  • 判断 当前字符是不是 \0
  • 如果是 返回 0;
  • 如果不是 返回 剩下的长度 + 1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值