台阶问题引出的递归和非递归的思考

一个台阶总共有n级,如果一次可以跳1级,也可以跳2级。求总共有多少总跳法,并分析算法的时间复杂度。

如果看到过这个题目的童鞋们,可能很快就有思路了,这个属于动态规划的典型题目。

基本思路如下:

假设n个台阶共有f(n)个跳法。那么我第一步可以跳1级,可以跳2级。

如果第一步跳1级,那么之后我有f(n-1)种跳法。

如果第一步跳2级,那么之后我有f(n-2)中跳法。

所以,得到下面的公式

一看到这个公式,很多人就会想到Finbonacci队列(兔子繁殖问题),很多人都是通过这个例子学会的递归方法。

代码如下:

<span style="font-size:18px;"><em>#include <iostream>
#include <time.h>

using namespace std;

int step(int n)
{
    if (n == 1)
        return 1;
    if (n == 2)
        return 2;
    return step(n-1) + step(n-2);
}

int main()
{
   int n;
   int result;
   cin>>n;
   time_t start = clock();
   result = step(n);

   cout<<result<<endl;
   time_t end = clock();
   cout<<double(end - start)/CLOCKS_PER_SEC<<endl;
   return 0;

}</em></span>

代码中有几个问题:

1 int 类型太小,可能很多时候会越界

2 没有进行参数检测。

但是运行的时候,发现n数字比较小的时候,还可以,但是如果输入30,就需要100秒了,输入100,可能需要几个小时(我没有等这个时间)

所以递归算法的时间,是几何形的增长。我感觉是的复杂度,对于复杂度不会求,后面有机会再补充。

于是就想把递归变成非递归。

计算机上面很多时候就是时间和空间的一个换算。非递归,就是从f(1)开始一步一步的推到f(n)

于是,我们得到f(0) = f(1)=1 那么

f(2) = f(0)+f(1)=2;

f(3)= f(1)+f(2) =3;

f(4) = f(2) +f(3) = 5;

可以看到f(n)需要记录两个变量f(n-1)和f(n-2)的数值,所以我们用变量a0 ,a1 分别表示,用循环替代递归

那么a2 = a0+a1;

a0 = a1;

a1 = a2;

注意上面的赋值顺序,先赋值a0,在赋值a1.

代码如下

<span style="font-size:18px;"><em>#include <iostream>
#include <time.h>

using namespace std;

int main()
{
   int n;
   int result;
   int a0 = 1;
   int a1 = 1;
   int a2 = 1;
   cin>>n;
   time_t start = clock();
   for (int i = 2; i <= n ; i++)
   {
       a2 = a0 + a1;
       //cout<<"a2 "<<a2<<endl;
       a0 = a1;
       a1 = a2;
    }   

   result = a2;
   cout<<result<<endl;
   time_t end = clock();
   cout<<double(end - start)/CLOCKS_PER_SEC<<endl;
   return 0;

}</em></span>

你在运行,输入大的数如50 100 也基本是瞬间完成的,他的效率应该是n级别。

所以,在理解程序上,递归简单一点,但是在效率上非递归要远远高于递归。所以需要根据自己的实际情况选择,最好都将递归改成非递归的方式。

台阶问题引出的递归和非递归的思考

时间: 2024-10-27 21:35:28

台阶问题引出的递归和非递归的思考的相关文章

数据结构——二叉树遍历之“递归与非递归遍历”

简述 二叉树的遍历分为先序遍历.中序遍历和后序遍历.如下图所示: 递归遍历 private void bianli1(List<Integer> list, TreeNode root) { // 先序遍历 if (root == null) { return; } list.add(root.val); bianli1(list, root.left); bianli1(list, root.right); } private void bianli2(List<Integer>

JAVA递归、非递归遍历二叉树(转)

原文链接: JAVA递归.非递归遍历二叉树 import java.util.Stack; import java.util.HashMap; public class BinTree { private char date; private BinTree lchild; private BinTree rchild; public BinTree(char c) { date = c; } // 先序遍历递归 public static void preOrder(BinTree t) {

Java数据结构系列之——树(4):二叉树的中序遍历的递归与非递归实现

package tree.binarytree; import java.util.Stack; /** * 二叉树的中序遍历:递归与非递归实现 * * @author wl * */ public class BiTreeInOrder { // 中序遍历的递归实现 public static void biTreeInOrderByRecursion(BiTreeNode root) { if (root == null) { return; } biTreeInOrderByRecursi

二叉树遍历递归与非递归实现

说明:本文仅供学习交流,转载请标明出处,欢迎转载! 二叉树遍历是二叉树中非常基础的部分,也是学习二叉树必须熟练掌握的部分,下面我们先给出二叉树三种遍历方式的定义,并通过举例来说明二叉树遍历的过程. 二叉树的遍历分为:前序遍历(也叫先序遍历).中序遍历.后序遍历.所谓前.中.后都是根据当前子树根结点相对左右孩子的位置而言,也就是说: 前序遍历:根结点在前,即:根 ----->左------->右: 中序遍历:根结点在中间,即:左------>根------>右: 后序遍历:根结点在最

树的递归与非递归遍历总结

树的递归遍历遍历很简单,非递归遍历要复杂一些,非递归先序.中序.后序遍历需要用一个辅助栈,而层次遍历则需要一个辅助队列. 树的结构: 1 public class Tree<T> { 2 private T data; 3 private Tree<T> left; 4 private Tree<T> right; 5 ... 6 } 用策略模式定义一个访问工具: 1 public interface Visitor<T> { 2 void process(

全排列(递归与非递归实现)

全排列问题在公司笔试的时候很常见,这里介绍其递归与非递归实现. 递归算法 1.算法简述 简单地说:就是第一个数分别以后面的数进行交换 E.g:E = (a , b , c),则 prem(E)= a.perm(b,c)+ b.perm(a,c)+ c.perm(a,b) 然后a.perm(b,c)= ab.perm(c)+ ac.perm(b)= abc + acb.依次递归进行. void swap(string &pszStr,int k,int m) { if(k==m) return ;

二叉树三种遍历(递归以及非递归实现)

package com.shiyeqiang.tree; import java.util.Stack; public class BiTree { public static void main(String[] args) { // 首先构造叶子节点 BiTree leafA1 = new BiTree(4); BiTree leafA2 = new BiTree(5); BiTree leafB1 = new BiTree(6); BiTree leafB2 = new BiTree(7)

二叉树遍历算法总结(递归与非递归)

一:前言 二叉树的遍历方法分四种:前序,中序,后序以及层次遍历. 其中,前中后遍历方法的实现分递归和非递归,非递归遍历的实现需要借助于栈. 实际上,递归的调用就是一种栈的实现,所以,非递归遍历就需要人工借助栈结构来实现. 而层次遍历需要借助队列. 二:前中后序遍历 递归遍历: 递归遍历的思想和方法很简单,通过调整输出语句来实现前,中,后三种遍历. 代码如下: 1 void show(BiTree T) 2 { 3 if(T) 4 { 5 printf("%c ",T->data)

链表反转的递归和非递归实现方式

链表反转是数据结构的基本功,主要有递归和非递归两种实现方式.我们一一介绍如下: 1. 非递归实现 主要包括如下4步: 1)如果head为空,或者只有head这一个节点,return head即可: 2)从头到尾遍历链表,把reversedHead赋值给当前节点的next: 3)当前节点赋值给reversedHead: 4)遍历结束,return reversedHead. 下图试图来辅助说明: 代码如下: node* reverseList(node* head) { if(head == NU