程序调用自身的编程技巧称为递归,递归作为一种算法在程序设计语言中广泛应用.一个过程或者函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来解决,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大的减少可程序的代码量,递归的主要思想在于: 吧大事化小.
// 完成从键盘输入一个无符号数,依次正序输出该数的每一个值
# define _CRT_SECURE_NO_WARNINGS 1
# include
void print(unsigned int i) {
if (i > 9) {
print(i / 10);
}
printf("%u ", i % 10);
}
int main()
{
unsigned int num = 0;
scanf("%u", &num);
print(num); //print函数打印出参数中的每一位
return 0;
}
为了避免死递归,递归有以下两个必要条件:
存在限制条件,当满足这个限制条件的时候,递归便不再继续
每次递归调用之后越来越接近这个限制条件.
注意以上条件为必要不充分条件, 不满足一定错,满足不一定对,下面给出满足却不对的例子:
# define _CRT_SECURE_NO_WARNINGS 1
# include
void test(int n) {
if (n < 10000) {
test(n + 1);
}
}
int main() {
test(1);
return 0;
}
表面上运行正常,编译时候出现报错
其实出现了代码挂断,因为这里发生了栈溢出,为什么会发生栈溢出呢?这还要从内存说起:
所以:写递归代码的时候,不能死递归,都有跳出条件,每次递归逼近跳出条件;并且递归层次不能太深.
防止程序出现栈溢出现象的方法:
第一当然是将递归改成非递归啦(划水)
第二是用static对象替代nonstatic局部变量(即栈对象),这不仅可以减少每次递归调用和返回时产生和释放nonstatic对象的开销,而且static对象还可以保存递归调用的中间状态,并且可为各个调用层所访问
练习:
编写函数不允许创建临时变量,求字符串长度:
先来一个试试水:
# define _CRT_SECURE_NO_WARNINGS 1
# include
int my_strlen(char* str)
{
int count = 0;
while (*str != '\0') {
count++;
str++;
}
return count;
}
int main()
{
char arr[] = "bit";
//模拟实现一个strlen函数
printf("%d", my_strlen(arr));
return 0;
}
# define _CRT_SECURE_NO_WARNINGS 1
# include
int my_strlen(char* str) {
if (*str != '\0') {
return 1 + my_strlen(str + 1);
}
else return 0;
}
int main()
{
char arr[] = "bit";
//模拟实现一个strlen函数
printf("%d", my_strlen(arr));
return 0;
}
# define _CRT_SECURE_NO_WARNINGS 1
# include
int Fab(int n) {
if (n <= 2)
return 1;
else {
return Fab(n - 1) + Fab(n - 2);
}
}
int main()
{
int n, ret;
scanf("%d", &n); //输入要获取第n个斐波那契数
ret = Fab(n);
printf("%d", ret);
}
当输入为50时:
原因:不是因为栈溢出了,是因为算法效率太低了,重复了大量的计算!等很长时间才能输出.
代码改进:
# define _CRT_SECURE_NO_WARNINGS 1
# include
//int Fab(int n) {
// if (n <= 2)
// return 1;
// else {
// return Fab(n - 1) + Fab(n - 2);
// }
//}
int Fab(int n) {
int a = 1;
int b = 1;
int c = 1;
while (n > 2) {
c = a + b;
a = b;
b = c;
n--;
}
return c;
}
int main()
{
int n, ret;
scanf("%d", &n); //输入要获取第n个斐波那契数
ret = Fab(n);
printf("%d", ret);
return 0;
}
//不用c语言库中字符串操作函数逆序"abcdef"并输出(迭代和递归)
递归:
# include
int my_len(char* str) {
int len = 0;
while (*str != '\0') {
len++;
str++;
}
return len;
}
void reverse_arr(char* str) {
char tem = *str;
int len = my_len(str);
char right = *(str + len - 1);
char left = tem;
*str = right;
*(str + len - 1) = '\0';
if (my_len(str + 1) >= 2) {
reverse_arr(str + 1);
}
*(str + len - 1) = tem;
}
int main()
{
char arr[] = "abcdef";
reverse_arr(arr);
printf("%s", arr);
return 0;
}
这道题迭代法更简单:
# include
int my_len(char* str) {
int len = 0;
while (*str != '\0') {
len++;
str++;
}
return len;
}
//递归:
//void reverse_arr(char* str) {
// char tem = *str;
// int len = my_len(str);
// char right = *(str + len - 1);
// char left = tem;
// *str = right;
// *(str + len - 1) = '\0';
// if (my_len(str + 1) >= 2) {
// reverse_arr(str + 1);
// }
// *(str + len - 1) = tem;
//}
//迭代:
void reverse_arr(char* str) {
int left = 0;
int right = my_len(str - 1);
while (left < right) {
char tem = *(str + left);
str[left] = str[right];
str[right] = tem;
left++;
right--;
}
}
int main()
{
char arr[] = "abcdef";
reverse_arr(arr);
printf("%s", arr);
return 0;
}
调试时显示Run-Time Check Failure #2 - Stack around the variable ‘arr’ was corrupted.
意思大概是运行时检查失败2-变量“arr”周围的堆栈已损坏。
原因是因为内存越界了,大概是数组下标访问越界了.
应该是int right = my_len(str) - 1;