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 != '\n')
recur();
cout<<c;
return 0;
}
int main()
{
recur();
return 0;
}
//若输入:abc \n
//打印顺序:\n 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 != '\0') {
recur();
cout << c;
}
return 1; //**句
}
int main() {
cin.getline(input, 501);
while (input[i] != '\0') {
if (recur() == 1)//***句
cout << ' ';
}
if (input[i] == '\0') {
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]={'\0'};
int i=0,j=0;
int cut()
{
int movement = 0;
int flag = 0;
for (int i = 0; i < 101; i++) {
if (a[i] != '\0')
flag = 1;
}
if(flag == 0)
return 0;
for (int i = 0; i < 101; i++) {
if(a[i]!='\0')
{
for (int j = i+1; j < 101; j++) {
if(a[j] == '\0')
continue;
if(a[j] == a[i])
break;
if(a[j] != a[i])
{
cout<<i<<' '<<j<<endl;
a[i] = '\0';
a[j] = '\0';
movement = 1;
break;
}
}
if(movement == 1)
break;
}
}
flag = 0;
for (int i = 0; i < 101; i++) {
if (a[i] != '\0')
flag = 1;
}
if(flag == 1)
cut();
}
int main()
{
cin.getline(a,100,'\n');
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<<'\n';
}
return 0;
}
Coursera课程笔记----C程序设计进阶----Week 3的更多相关文章
- Coursera课程笔记----C程序设计进阶----Week 5
指针(二) (Week 5) 字符串与指针 指向数组的指针 int a[10]; int *p; p = a; 指向字符串的指针 指向字符串的指针变量 char a[10]; char *p; p = ...
- Coursera课程笔记----C程序设计进阶----Week 4
指针(一) (Week 4) 什么是"指针" 互联网上的资源--地址 当获得一个地址,就能得到该地址对应的资源,所以可以把"网址"称为指向资源的"指针 ...
- Coursera课程笔记----C程序设计进阶----Week 1&2
C程序中的函数(Week 1&2) 函数 函数的定义 对函数的普遍认识:y=f(x) C语言中的常用函数: 平方根: r = sqrt(100.0) 底数x的y次幂:k = pow(x,y) ...
- Coursera课程笔记----C++程序设计----Week3
类和对象(Week 3) 内联成员函数和重载成员函数 内联成员函数 inline + 成员函数 整个函数题出现在类定义内部 class B{ inline void func1(); //方式1 vo ...
- 操作系统学习笔记----进程/线程模型----Coursera课程笔记
操作系统学习笔记----进程/线程模型----Coursera课程笔记 进程/线程模型 0. 概述 0.1 进程模型 多道程序设计 进程的概念.进程控制块 进程状态及转换.进程队列 进程控制----进 ...
- Coursera课程笔记----Write Professional Emails in English----Week 3
Introduction and Announcement Emails (Week 3) Overview of Introduction & Announcement Emails Bas ...
- Coursera课程笔记----Write Professional Emails in English----Week 1
Get to Know Basic Email Writing Structures(Week 1) Introduction to Course Email and Editing Basics S ...
- Coursera课程笔记----计算导论与C语言基础----Week 6
理性认识C程序 导论(Week 6) 明确学习进度 讲课内容 感性➡️理性➡️函数➡️指针等 作业练习 初级阶段 ➡️正常作业练习 C语言的由来 程序设计语言的分类 低级语言之机器语言 0010101 ...
- Coursera课程笔记----计算导论与C语言基础----Week 4
感性认识计算机程序(Week 4) 引入 编程序 = 给计算机设计好运行步骤 程序 = 人们用来告诉计算机应该做什么的东西 问题➡️该告诉计算机什么?用什么形式告诉? 如果要创造一门"程序设 ...
随机推荐
- Nginx+uWSGI+Python+Django构建必应高清壁纸站
写在前面 做这个网站的初衷是因为,每次打开必应搜索搜东西的时候都会被上面的背景图片吸引,我想必应的壁纸应该是经过专业人员精选出来的,我甚至会翻看以前的历史图片,唯一美中不足的是必应的首页只能查看最多7 ...
- [译]谈谈SpringBoot 事件机制
要"监听"事件,我们总是可以将"监听器"作为事件源中的另一个方法写入事件,但这将使事件源与监听器的逻辑紧密耦合. 对于实际事件,我们比直接方法调用更灵活.我们可 ...
- 详解 Hashtable
至于HashTable,本人只想说,除了它们各自的特点是截然相反外,其余性质 以及 用法和HashMap的性质几乎一样, (有关Map集合的基本性质,请观看本人博文-- <详解 Map集合> ...
- spark 集群优化
只有满怀自信的人,能在任何地方都怀有自信,沉浸在生活中,并认识自己的意志. 前言 最近公司有一个生产的小集群,专门用于运行spark作业.但是偶尔会因为nn或dn压力过大而导致作业checkpoint ...
- python 规范篇 如何合理使用 assert
assert 的合理使用,可以增加代码的健壮度,同时也方便了程序出错时开发人员的定位排查. 什么是 assert? Python 的 assert 语句,可以说是一个 debug 的好工具,主要用于测 ...
- Win10桌面美化
捯饬了几个小时终于捯饬好了,没什么特效,就是看起来干净了许多. 用到的小软件: 链接:https://pan.baidu.com/s/1_PSTn0JZ22ZGiMDOdvdWEw提取码:329c 1 ...
- CSS中“~”(波浪号)、“,”(逗号)、“+”(加号)、“>”(大于号)、“ ”(空格)详解
“~”:$('pre ~ brother')表示获取pre节点的后面的所有兄弟节点,相当于nextAll()方法: “+”:$('pre + nextbrother')表示获得pre节点的下一个兄弟节 ...
- PHP $_FILES的应用
关于文件上传这块,如果处理不好的话,很容易成为黑客入侵的开口,例如黑客在你这个上传接口里放一段木马的文件,那只能祝你好运了. 所以,我们上传文件的时候都会先判断, 但是一般的操作是先上传,再判断,如果 ...
- 梁国辉获Yes评分表系统3.0计算机软件著作权
梁国辉获Yes评分表系统3.0计算机软件著作权 Liang Guohui won the Yes score system 3 computer software copyright 登记证书如下 R ...
- [redis]SDS和链表
一.SDS 1.SDS结构体 redis3.2之前:不管buf的字节数有多少,都用 4字节的len来储存长度,对于只存短字符串那么优点浪费空间,比如只存 name,则len=4 则只需要一个字节8位即 ...