目录
写在前面
原来想做一个能系统且全面回答:循环的应用场景?迭代能解决的问题,递归一定能解决嘛?递归能解决的问题,迭代一定能解决吗?能,具体代码如何由此及彼,不能,具体限制的原因是什么?但笔者查阅资料后,发现问题比较复杂,就先分享出初阶的结论,并且本文会不定期更新。
关键词
循环是程序设计语言中一种用于反复执行某些代码的处理过程。
迭代是指重复反馈过程的活动,每一次迭代的结果会作为下一次迭代的初始值。
递归是一种编程技巧,它允许函数调用自身来解决问题。
一.循环
解释
我们要循环是因为接下来我们要做的事是同构的,即有相似或相同之处。在循环控制中,最重要的就是循环条件。如果处理不好,就有可能陷入死循环,造成内存溢出,main函数最终不返回0
循环的类型
1.已知循环长度的有限循环
for(int i = 0;i <= 10;i++)
//
while(i)
{
//省略的代码
i--
}
这种代码较好理解,就不过多赘述了。在这里要补充的是一个不容易想到的关于初始化是字符的:
简单但不好想的猜凶手
日本某地发生了一件谋杀案,警察通过排查确定杀人凶手必为4个嫌疑犯的一个。
以下为4个嫌疑犯的供词:
A说:不是我。
B说:是C。
C说:是D。
D说:C在胡说
已知3个人说了真话,1个人说的是假话。
现在请根据这些信息,写一个程序来确定到底谁是凶手。
#include<stdio.h>
int main()
{
int killer = 0;
//分别假设凶手是a,b,c,d,看谁是凶手时满足3个人说了真话,一个人说了假话
for (killer = 'a'; killer <= 'd'; killer++)
{
if ((killer != 'a') + (killer == 'c') + (killer == 'd') + (killer != 'd') == 3)
printf("凶手是:%c", killer);
}
return 0;
}
本题有两个简单难想的点,1是初始化的不是整型而是字符,2是三真一假的表示。
2.未知长度有限循环
未知长度在于,每一次循环的长度都有可能不一样,有限循环在于他一定有尽头,循环条件的真假一般与我们的输入密切相关。
int arr[1000] = { 0 };
int count = 0;
do
{
scanf("%d", &arr[count]);
count++;
} while (getchar() != '\n');
比如上一期博客未定长度的整型数组的输入,数组的长度是由我们控制的,循环次数当然也是由我们控制的。再比如有些游戏用input的输入来控制循环的发生:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void menu()
{
printf("*********************\n");
printf("********1.开始********\n");
printf("********0.结束********\n");
printf("*********************\n");
}
void game()
{
srand((unsigned int)time(NULL));
int goal = rand() % 100;
int k = NULL;
while (goal != k)
{
printf("请输入数字:>>");
scanf("%d", &k);
if (goal > k)
{
printf("猜小了\n");
}
else if (goal < k)
{
printf("猜大了\n");
}
}
if (goal == k)
{
printf("恭喜你,猜对了\n");
}
}
int main()
{
int input = 0;
do
{
menu();
printf("请输入数字:>>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出\n");
break;
default:
printf("请重新输入\n");
break;
}
} while (input);
return 0;
}
这种类型的循环主要是刚开始的意识问题,不知道可以这么玩。
3.未知长度的无限循环
这种循环是没有意义的,没有尽头,有也只是内存泄漏——迭代只是时间问题,递归更不用说——本质都是没有“终止条件”。
二.递归——数学归纳法
迭代与普通的循环无异,主要是递归。当一个函数调用自己时,一般要用到if,else语句,用来表明循环结束的条件。写一个递归函数,要在写完基本情况的情况下,明确递归函数能干什么,想象它已经写完了。然后再调用。注意最后一定会收敛于基本情况。
1.阶乘
#include<stdio.h>
int fun(int n)
{
if(n==1||n==0) return 1;//如果参数是0或者1返回1
return n*fun(n-1);//否则返回n和下次递归的积
}
int main()
{
int n;
scanf("%d",&n);
printf("%d\n",fun(n));
return 0;
}
基本情况是0和1,确定好返回值后,对于一般情况,假设已经写完后,调用自身,最终收敛于基本情况,就一定能递归出来。
尾递归优化
#include<stdio.h>
int jiecheng(int n,int m)
{
if (n == 0 || n == 1)
{
return m;
}
else
{
return jiecheng(n - 1,m*n);
}
}
int main()
{
int n = 8;
while (1)
{
scanf("%d", &n);
int ret = jiecheng(n, 1);
printf("%d\n", ret);
}
return 0;
}
2.汉诺塔问题
#include<stdio.h>
int count = 0;
hanoi(int n, char A, char B, char C)
{
if (n == 0)
return;
else if (n == 1)
{
count++;
printf("第%d步\n", count);
printf("%c->%c\n", A, C);
}
else
{
hanoi(n - 1, A, C, B);
count++;
printf("第%d步\n", count);
printf("%c->%c\n", A, C);
hanoi(n - 1, B, A, C);
}
}
int main()
{
int n = 0;
scanf("%d", &n);
hanoi(n, 'A', 'B', 'C');
printf("总共用了%d步", count);
getchar();
main();
return 0;
}
写出递归函数真不用知道他在计算机中到底是怎么跑的,假设已经写完,再写出他的一个子问题即可。
3.斐波那契数列
#include<stdio.h>
double fib(int n)
{
if (n <= 2)
{
return 1;
}
else
{
return fib(n - 2) + fib(n - 1);//递归思想
}
}
int main()
{
int n = 0;
double ret = 0;
scanf("%d", &n);
ret = fib(n);
printf("第%d个斐波那契数字是%.0lf",n, ret);
return 0;
}
尾递归优化
long long fib(long long first,long long second,size_t n)
{
if(n<2)
{
return n;
}
if(2 == n)
{
return first+second;
}
return fib(second,first+second,n-1);
}
三.迭代与递归的关系
递归中的基本情况(==0或==1时的情况),就好比迭代中的循环条件;
递归中的一般情况的“递”,不断减一,类似于i--
其它就类比于循环体,像阶乘,斐波那契数列改成迭代都比较简单,但汉诺塔实在也没想明白。
我会不断学习,争取早日填坑。感谢大家的观看和大佬的指点!!!
本文探讨了循环、迭代和递归在编程中的应用,包括有限长度循环的实例、未知长度循环的处理、递归的数学归纳法原理如阶乘、汉诺塔和斐波那契数列,以及尾递归优化。作者强调了递归和迭代的关系,并承诺后续会继续深入探讨这些主题。
1691





