什么是递归?
程序调用自身的编程技巧称为递归(recursion)。
递归作为一种算法在程序设计语言中广泛应用。
一个过程或函数在其定义或说明中有直接或间接调用自身的一种方式。
它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复的计算,大大地减少了程序地代码量。递归的主要思考方式在于:把大事化小
最简单的递归,那为什么它是错误的❌??
//最简单的错误递归 #include<stdio.h> int main() { printf("haha\n"); main(); return 0; }
因为它没有限制条件。
递归的条件
1.存在限制条件,当满足这个限制条件的时候,递归便不在继续。
2.每次递归调用之后越来越接近这个限制条件。
练习NO1.
//接受一个整型值(无符号),按照顺序打印它的每一位。 //例如: 输入:1234,输出 1 2 3 4.
按照我们传统方式:
//传统方式 #include<stdio.h> int main() { //1234%10=4 //1234/10=123 //依次取模和除法 int a = 0; int num = 0; scanf("%d", &a); while (a)//a除以到最后1/10得0.1不是整数表达式,跳出循环 { num = a % 10; printf("%d ", num); a = a / 10; } return 0; }
我们今天学习到递归,我们就用递归得逻辑实现这个问题。(函数自己调用自己实现递归逻辑)
//递归逻辑 //Print能将参数得num得每一位打印在屏幕上 //Print(1234) //Print(123) +4 //Print(12)+3+4 //Print(1)+2+3+4
#include<stdio.h> void Print(int a)//1234 { if(a > 9)//a是两位数,当a是一位数时跳出循环 { Print(a/10); } printf("%d ", a%10); } int main() { int a = 0; scanf("%d", &a); Print(a); return 0; }
讲解如下:
理解到程序到底是怎样执行的。
变量a是怎样改变的。
递归:递进 回归。
Point1.用while
#include<stdio.h> void Print(int a)//1234 { while(a > 9) { Print(a / 10); } printf("%d ", a % 10); } int main() { int a = 0; scanf("%d", &a); Print(a); return 0; }
所以即使加了限制条件的递归也不一定是正确的,但不加限制条件绝对是错误的❌。
必要条件必须要有,有不一定对,没有一定错。❌
循环和分支使用适合。
Point2.用a=a/10
#include<stdio.h> void Print(int a)//123 { if(a > 9) { a = a / 10; Print(a); } printf("%d ", a%10); } int main() { int a = 0; scanf("%d", &a); Print(a); return 0; }
所以尽量直接写,不要用赋值去改变某个变量。
根本原因
函数之所以能实现,能实现递归。
都是因为,函数在调用的时候会维护一个函数栈帧(内存上的一块区域)。
函数调用开始,函数栈帧创建,函数调用结束后,栈帧销毁。
关于函数栈帧创建和销毁,后面会详细介绍。✔✔✔✔
练习NO2.
//编写函数不允许创建临时变量,求字符串的长度。
求字符串长度strlen和sizeof
#include<stdio.h> int main() { char arr[] = "abc"; size_t str = strlen(arr); printf("%zd", str); return 0; }
size_t 是一种类型,是无符号整型的。
size_t 就是为sizeof设计的
size_t l类型的数据打印的时候使用%zd
strlen包含头文件#include<string.h>
strlen只计算\0之前的字符个数。
sizeof计算\0。
让我们编写函数求字符串长度,也就是模拟strlen的功能(传统方式)。
arr指的是字符串首元素的地址 指针变量str来接受 *str指的是元素 str指的是地址 str++可以让地址往后移动 count计算 *str依次跟着往后移动 直到*str == '\0'就停止循环 返回count计算元素的个数
size_t my_strlen(char* str)//把数组第一个字符地址传过去 { int count = 0; while (*str != '\0') { str++; count++; } return count; } #include<stdio.h> int main() { char arr[] = "abc"; size_t str=my_strlen(arr);//编写函数求字符串长度 printf("%zd", str); return 0; }
函数递归的思想:大事化小来解决问题呢!
递归求字符串长度 //my_strlen("abc"); //1+my_strlen("bc"); //1+1+my_strlen("c"); //1+1+1+my_strlen("\0"); //1+1+1+0=3
size_t my_strlen(char* str)//把数组第一个字符地址传过去 { if (*str == '\0') return 0; else return 1 + my_strlen(str + 1); } #include<stdio.h> int main() { char arr[] = "abc"; size_t str = my_strlen(arr);//编写函数求字符串长度 printf("%zd", str); return 0; }
讲解如下:
Point1.str++和++str和str+1
str++:
++str :
str++是先使用了my_strlen函数在+1
++str是先+11再使用my_strlen函数
最好还是使用str+1,++在其他情况下可能会改变str的前后的值,有副作用。