Coursera课程笔记----C程序设计进阶----Week 3

函数的递归(Week 3)

什么是递归

  • 引入
    • 函数可以嵌套调用:无论嵌套多少层,原理都一样
    • 函数不能嵌套定义:不能在一个函数里再定义另一个函数,因为所有函数一律平等
    • 问题:一个函数能调用它自己吗?
  • 举递归调用的简单例子
#include<iostream>
using namespace std;
int fact(int n)
{
  if(n == 1)
    return 1;
  else
    return n*fact(n-1);
}
int main(){
  cout<<fact(4)<<endl;
  return 0;
}
  • 递归调用与普通的函数调用一样
    • 函数调用时,总是开辟新内存空间放调用的函数,递归调用同理

深入理解递归过程

#include<iostream>
using namespace std;
int recur()
{
  char c;
  c = cin.get();
  if(c != '
')
    recur();
  cout<<c;
  return 0;
}
int main()
{
  recur();
  return 0;
}
//若输入:abc 

//打印顺序:
 cba

递归的作用

用递归完成递推

  • 再一次切饼
#include<iostream>
using namespace std;

int q(int n)
{
  if(n == 0)
    return 1;
  else
    return(n+q(n-1));
}
int main()
{
  cout<<q(4)<<endl;
  return 0;
}
//只需递推式和边际条件就能写出递归
  • 递归与递推

    • 不同
      • 递推的关注点放在起始点条件(i=0 ➡️ i=n)
      • 递归的关注点放在求解目标上(i=n ➡️ i=0)
    • 相同
      • 重在表现第i次与第i+1次的关系
  • 用递归实现递推

    • 优点

      • 让程序变得简明
    • 方法

      • 把关注点放在要求解的目标

        从而

      • 找到第n次做第n-1次做之间的关系

      • 确定第1次的返回结果

  • 斐波那契数列

#include <iostream>
using namespace std;
int f(int n)
{
  if(n==1)
    return 1;
  if(n==2)
    return 2;
  else
    return(f(n-1)+f(n-2));
}
int main()
{
  cout<<f(4)<<endl;
}

模拟连续发生的动作

  • 进制转换
#include<iostream>
using namespace std;
void convert(int x)
{
  if((x / 2) != 0)
  {
    convert(x / 2);
    cout<<x % 2; //把cout放在递归调用之后,就可以逆序打印出来
  }
  else
    cout<<x;
}

int main()
{
  int x;
  cin >> x;
  convert(x);
  return 0;
}


  • 汉诺塔问题
#include <iostream>
using namespace std;
void move(int m, char x, char y, char z) //将m个盘子从A经过B移动到C
{
  if(m == 1)
  {
    cout<<"把一个盘子"从<<x<<"移动到"<<z<<endl;
  }
  else
  {
    move(m-1,x,z,y);
		cout<<"把一个盘子"从<<x<<"移动到"<<z<<endl;
    move(m-1,y,x,z);
  }
}
int main()
{
  int n;
  cout<<"请输入盘数n=";
  cin >> n;
  cout<<"在三根柱子上移动"<<n<<"只盘的步骤为:"<<endl;
  move(n,'A','B','C');
  return 0;
}
  • 思考的方法
    • 搞清楚连续发生的动作是什么(定义函数)
    • 搞清楚 不同次动作之间的关系(描述递归函数之间的关系)
    • 搞清楚边界条件是什么(递归退出的边际条件)

进行“自动的分析”

  • 放苹果
    • 把M个苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?
    • 注意:5,1,1和1,5,1是同一种放法
    • 输入:7,3
    • 假设:有一个函数f(m,n)能告诉我答案
      • 如果:n/盘子数 > M/苹果数: f(n>m)➡️f(m,n)=f(m,m)
      • 如果:M/苹果数>=n/盘子数
        • 有盘子空着:f(m,n) = f(m,n-1)
        • 没盘子空着:f(m,n) = f(m-n,n)
#include <iostream>
using namesapce std;
int count(int m,int n)
{
  if( m<= 1 || n <=0) return 1;
  if(m < n)
    return count(m,m);
  else
    return count(m,n-1) + count(m-n,n)
}
void main()
{
  int apples,plates;
  cin >> apples >> plates;
  cout << count(apples,plates);
}
  • 逆波兰表达式
    • 拟波兰表达式
      • 一种把运算符前置的算术表达式(2 + 3 ➡️ + 2 3)
      • 编写程序求解任意仅包含+ - * /四个运算符的逆波兰表达式
#include <iostream>
using namespace std;
double notation()
{
  char str[10];
  cin >> str;
  switch(str[0])
  {
      case '+' return notation()+notation();
      case '-' return notation()-notation();
      case '*' return notation()*notation();
      case '/' return notation()/notation();
    default: return atof(str);
  }
}

int main()
{
  cout<<notation();
  return 0;
}
//注意这个题目的数据输入方式
  • 在以上复杂的场景中,递归帮我们进行了“自动分析”
    • 方法
      • 先假设有一个函数能给出答案
      • 在利用这个函数的前提下,分析如何解决问题
      • 搞清楚最简单的情况下,答案是什么

习题

Quiz1 单词翻转

#include<iostream>
using namespace std;
int i = 0;
char input[501];
int recur() {
    char c = input[i];
    i++;
    if (c == ' ') {
        return 1;//*句
    }
    if (c != ' '&&c != '') {
        recur();
        cout << c;
    }
    return 1; //**句
}
int main() {
    cin.getline(input, 501);
    while (input[i] != '') {
        if (recur() == 1)//***句
            cout << ' ';

    }
    if (input[i] == '') {
        cout << endl;//最后输出换行符
        return 0;
    }
}
//详解:
//以输入'Hello  World'为例,句***刚被执行时,i=0,当被执行的这次return返回来时,i=6;句***再次被执行时,i=7,当被执行的这次return返回来时,i=8(因为只取了一个空格)
//遇到第一个空格时*句的return内容被"吞"掉了,所以需要**句的存在来补上这一个return
//最终的输出是'olleh  dlrow',其中第一个空格来自**句,第二个空格来自*句

Quiz2 角谷猜想

#include <iostream>
using namespace std;
int JGG(int x)
{
    if(x == 1)
    {
        cout<<"End"<<endl;
        return 0;
    }
    else if(x % 2 == 0)
    {
        cout << x << "/2="<< x/2<<endl;
        JGG(x/2);
    }
    else
    {
        cout << x <<"*3+1="<< (x*3+1)<<endl;
        JGG(x*3+1);
    }
    return 0;
}

int main()
{
    int n;
    cin >> n;
    JGG(n);
    return 0;
}

Quiz3 排队游戏

#include <iostream>
using namespace std;
char a[101]={''};
int i=0,j=0;

int cut()
{
    int movement = 0;
    int flag = 0;
    for (int i = 0; i < 101; i++) {
        if (a[i] != '')
            flag = 1;
    }

    if(flag == 0)
        return 0;
    for (int i = 0; i < 101; i++) {
        if(a[i]!='')
        {
            for (int j = i+1; j < 101; j++) {
                if(a[j] == '')
                    continue;
                if(a[j] == a[i])
                    break;
                if(a[j] != a[i])
                {
                    cout<<i<<' '<<j<<endl;
                    a[i] = '';
                    a[j] = '';
                    movement = 1;
                    break;
                }
            }
            if(movement == 1)
                break;
        }

    }

    flag = 0;
    for (int i = 0; i < 101; i++) {
        if (a[i] != '')
            flag = 1;
    }
    if(flag == 1)
        cut();
}

int main()
{
    cin.getline(a,100,'
');
    cut();
    return 0;
}

Quiz4 扩号匹配问题

#include <iostream>
#include <stack>

//双返回值的递归方法我实在有点看不懂(也不知道有没有非看懂不可的必要
//反正用堆栈就能很好的解决了……
using namespace std;
int main()
{
    string str;
    while(cin >> str) {


        char simple[101];
        for (int i = 0; i < str.length(); i++) {
            if (str[i] == '(')
                simple[i] = '$';
            else if (str[i] == ')')
                simple[i] = '?';
            else simple[i] = ' ';
        }

        stack<char> s;
        stack<int> index;
        for (int i = 0; i < str.length(); i++) {
            if (str[i] == '(') {
                s.push('(');
                index.push(i);
            }
            if (str[i] == ')') {
                if (!s.empty() && s.top() == '(') //&&两边的两个条件必须且顺序不能改!!!!!
                {
                    simple[index.top()] = ' ';
                    index.pop();
                    s.pop();
                    simple[i] = ' ';
                } else {
                    s.push(')');
                    index.push(i);
                }
            }
        }

        cout << str << endl;
        for (int i = 0; i < str.length(); i++) {
            cout << simple[i];
        }
        cout<<'
';

    }
    return 0;
}
原文地址:https://www.cnblogs.com/maimai-d/p/12824965.html