循环结构(四)——循环嵌套

news2024/12/24 9:24:39

🚀欢迎互三👉程序猿方梓燚 💎💎
🚀所属专栏:C++教程💎

🚀关注博主,后期持续更新系列文章

🚀如果有错误感谢请大家批评指出,及时修改

🚀感谢大家点赞👍收藏评论✍  

🍁引言

在编程的世界里,循环结构是实现重复操作的强大工具。而当循环与循环相互嵌套时,就如同打开了一扇通往更复杂、更强大逻辑的大门。循环嵌套就像是一个精心编排的舞蹈,外层循环掌控着整体的节奏,内层循环则在其中演绎着细腻的动作。

想象一下,要绘制一个复杂的图案,外层循环决定了图案的行数,内层循环则雕琢着每行中的细节。又或者在处理大量数据时,外层循环遍历不同的数据集,内层循环则对每个数据集中的元素进行精确操作。

例如,在生成乘法表的程序中,外层循环控制行数,内层循环控制列数,两者相互配合,才能准确无误地展示出乘法运算的结果。再比如,要找出一个二维数组中的最大值,就需要通过循环嵌套来遍历数组的每一个元素。

循环嵌套让我们能够解决那些看似棘手、实则充满规律的问题,它是编程中的艺术,也是提升程序效率和灵活性的关键。接下来,让我们深入探索循环嵌套的奥秘,开启编程的新篇章。

🍁例题

🚀例1

求 S=1!+2!+3!+....+10!    

分析:这个问题是求10以内自然数的阶乘之和,可以用for循环来实现。程序结构如下:

for(i=1;i<=10;++i) {   
    (1)i阶乘的值存到t;    //t=i!
    (2)累加t到s中;       //s+=t
}

 显然根据以上结构,通过10次的循环可以求出1!,2!,…10!,并不断累加起来,求出s。而求t=i!,又可以用一个for循环来实现:

t=1;
for (j=1;j<=i;++j)
    t*=j;

因此整个程序为:

#include <iostream>
using namespace std;
int main (){
    int t,s;
    s=0;
    for(int i=1;i<=10;++i) {
        t=1;
        for (int j=1;j<=i;++j)            //求i!
            t*=j;
            s+=t;                           //累加i!
    }
    return 0;
}

以上程序是一个for循环的嵌套。这种方法是比较容易想到的,但实际上对于求i!,我们可以根据求出的(i-1)!乘上i即可得到,而无需重新从1再累乘到i。

🚀例2

对于给定的自然数n(n<20),在屏幕上输出仅由“*”构成的n行的直角三角形。 例如:当n=5时,输出: 

【分析】打印图形总是逐行进行的,本题要重复n行操作,对于每一行,又重复若干次输出“*”操作。于是,构成了一个两层循环:外层循环是1至n行的处理,而内层循环,则是输出同一行上的每一列。分析样例,不难发现,每一行上“*”的个数恰好是行数。因此对于第i行,内层循环可以设置重复i次。

程序如下:

#include <iostream>
using namespace std;
int main () {
	int i, j, n;
	cin >> n;
	for (i = 1; i <= n; ++i) { //外层循环,控制行数
		for (j = 1; j <= i; ++j) //内层循环,输出一行中的*数
			cout << "*";
		cout << endl;        //每行最后要换行
	}
	return 0;

}

🚀例3

百钱买百鸡问题。鸡翁一,值钱五,鸡母一,值钱三,鸡雏三,值钱一,百钱买百鸡,问鸡翁、鸡母、鸡雏各几何?

💎【方法1】

在数学中解决这个问题,我们通常会列出一个方程组,设鸡翁x,鸡母y,鸡雏z,则:     x+y+z=100    

5*x+3*y+z/3=100    

同时满足上述两个方程的x、y、z值就是所求。    

根据这个思路,问题就转化为求解方程组,我们列举x、y、z的所有可能解,然后判断这些可能解是否能使方程组成立。能使方程组成立的,就是真正的解。    

再进一步分析,x的取值范围是1~100/5,y的取值范围是1~100/3,z的取值范围是1~3*100。

程序如下:

#include <iostream>
using namespace std;
int main() {
	int x, y, z;
	for (x = 0; x <= 100 / 5; x++) //列举鸡翁数的所有可能
		for (y = 0; y <= 100 / 3; y++) //列举鸡母数的所有可能
			for (z = 0; z <= 3 * 100; z++) //列举鸡雏数的所有可能
				if (5 * x + 3 * y + z / 3 == 100 && x + y + z == 100 && z % 3 == 0) //满足两个方程组
					cout << x << " " << y << " " << z << endl; //输出x、y、z值
	return 0;
}

运行结果:

【说明】     这里用了一个三层循环的程序解决问题。当x取得一个数值时,for的y循环体都要执行遍y的所有取值;当y取得一个数值时,for的z循环体都要执行遍z的所有取值;对于z的每一个取值,if语句都要执行一次。     不难算法,在程序的执行过程中,作为最内层循环体的if语句,将被执行:(1+100/5)*(1+100/3)*(1+3*100)=214914次。而观察程序的运行结果,问题的解远远小于这个数字,只有4组解。如何减少循环次数呢?

💎【方法2】

由于题目的特殊性,鸡翁、鸡母、鸡雏共100只,一旦确定鸡翁x和鸡母y的数量,鸡雏便只能购买100-x-y只。这样,我们可以尝试写出一个两层循环的程序,解决这个问题。 程序如下:

#include <iostream>
using namespace std;
int main() {
	int x, y, z;
	for (x = 0; x <= 100 / 5; x++) //列举鸡翁数的所有可能
		for (y = 0; y <= 100 / 3; y++) { //列举鸡母数的所有可能
			z = 100 - x - y;           //根据x,y计算鸡雏的数量
			if (5 * x + 3 * y + z / 3 == 100 && z % 3 == 0) //判断总钱数是否符合条件
				cout << x << " " << y << " " << z << endl; //输出x、y、z值
		}
	return 0;
}

【说明】对于与本题类似的求解不定方程问题,都可以用循环来求解。为提高效率,可以在程序中进行适当优化,减少循环体的执行次数。

🚀例4

求100-999中的水仙花数。若三位数ABC,ABC=A3+B3+C3,则称ABC为水仙花数。 例如153,13+53+33=1+125+27=153,则153是水仙花数。

【分析】 根据题意,采用三重循环来求解。由于循环次数一定,用for循环最为简单。

程序如下:

#include<iostream>
#include<iomanip>                            //调用setw函数需注明使用该库
using namespace std;
int main() {
	for (int a = 1; a <= 9; ++a)
		for (int b = 0; b <= 9; ++b)
			for (int c = 0; c <= 9; ++c) {
				if (a * a * a + b * b * b + c * c * c == a * 100 + b * 10 + c)
					cout << setw(6) << a * 100 + b * 10 + c; //setw函数控制输出场宽
			}
	return 0;
}

运行结果:

同时也可以采用一个for循环来求解,表面上看好像优于三重循环,实际上却比上面的程序效率低,请同学们自己分析。

程序如下:

#include<iostream>
#include<iomanip>
using namespace std;
int main() {
	int a, b, c;
	for (int m = 100; m <= 999; ++m) {
		a = m / 100; 		      //m的百位
		b = (m % 100) / 10; 		 //m的十位
		c = m % 10;                   //m的个位
		if (a * a * a + b * b * b + c * c * c == m)
			cout << setw(6) << m;
	}
	return 0;
}

🚀例5

输出100—200中所有的素数。

分析:我们可对100-200之间的每一个整数进行判断,若它是为素数,则输出。而对于任意整数i,根据素数定义,我们从2开始,到sqrt(i),找i的第一个约数,若找到第一个约数,则i必然不是素数。

程序如下:

#include <iostream>  
#include<cmath>                            //在Dev C++中可调用数学函数库cmath
using namespace std;
int main ()
{
  int x;
  for (int i=100;i<=200;++i)
  {
     x=2;
     while(x<=floor(sqrt(i))&&(i%x!=0))    //floor为取整函数,需调用math.h库
     x=x+1;                       //在枚举的范围内并且没有出现约数则继续枚举
     if ( x>floor(sqrt(i)))
       cout<<i<<"\t";
  }
  return 0;
}

🚀例6

【分析】分支和循环结合在一起时威力特别强大:我们枚举所有可能的aabb,然后判断它们是否为完全平方数。注意,a的范围是1~9,b可以是0。主程序如下:

for (a=1; a<=9; a++)
      for (b=0; b<=9; b++)
        if (aabb是完全平方数) printf("%d\n",aabb);

另一个思路是枚举平方根x,参考程序如下:

#include<cstdio>
int main()
{
	int n=0,hi,lo;
	for (int x=1 ;  ; ++x)                //可以直接从x=32开始枚举
	{
		n=x*x;
	 	if (n<1000) continue;
	 	if (n>9999) break;
	 	hi = n/100;
		lo = n%100;
		if (hi/10 == hi%10 && lo/10 == lo%10) printf("%d\n",n);
	}
	return 0;
}

此程序中的新东西是continue和break语句。continue是指跳回for循环的开始,执行调整语句并判断循环条件,就是“直接进行下一次循环”,而break是指直接跳出循环。     另外,注意到这里的for语句是“残缺”的:没有指定循环条件。事实上,3个部分都是可以省略的。没错,for(;;)就是一个死循环—如果不采取措施(如break),它就永远不会结束。

🚀例7

把一个合数分解成若干个质因数乘积的形式(即求质因数的过程)叫做分解质因数。分解质因数(也称分解素因数)只针对合数。     输入一个正整数n,将n分解成质因数乘积的形式。

输入样例:     36

输出样例:     36=2×2×3×3

【分析】    

将任意的n分解为质因数的乘积,要从最小的质数开始,那么,我们就不妨从2开始试除,能整除就输出2,再对商继续试除,直到不再含有因子2;然后用下一个质数反复试除,……,再用下一个质数试除,……,一直到商为1,停止操作。    

这里,质因数的递增,是一层循环,每一个质因数的反复试除,又是一层循环。因此,本题使用两层循环来解决。

程序如下:

#include <iostream>
using namespace std;
int main() {
	int n, i = 2;
	cin >> n;
	cout << n << "=";
	do  {
		while (n % i == 0) { //n能被i整除,就重复做除法操作
			cout << i;
			n /= i;
			if (n != 1)
				cout << "×";
		}
		i++;
	} while (n != 1);        //n没有除尽,就重复操作
	return 0;
}

🚀例8

阶乘之和     输入n,计算S=1! + 2! + 3! + … + n!的末6位(不含前导0)。n<=106, n!表示前n个正整数之积。    

样例输入:10    

样例输出:37913

【分析】     这个任务并不难,引入累加变量S之后,核心算法只有一句话:
 

for (i=1;i<=n;i++)
        S+=i!

不过C++语言并没有阶乘运算符,所以这句话只是伪代码,而不是真正的代码。事实上,我们还需要一次循环来计算i!:

for (j=1;j<=i;++j) 
    factorial*=j;

代码如下:

#include<cstdio>
int main()
{
	int n,s=0;
	scanf("%d",&n);
	for (int i=1;i<=n;++i)
	{
		int factorial=1;
		for (int j=1;j<=i;++j)
		  factorial*=j;
		s+=factorial;		
	}
	printf("%d\n",s%1000000);
	return 0;
}

注意累乘器factorial(英文“阶乘”的意思)定义在循环里面。换句话说,每执行一次循环体,都要重新声明一次factorial,并初始化为1(想一想,为什么不是0)。因为只要末6位,所以输出时对10^6取模。

当n=100时,输出-961703,直觉告诉我们:乘法溢出了。这个直觉很容易通过“输出中间变量”法得到验证,但若要解决这个问题,还需要一点数学知识。试一下n=106时输出什么?更会溢出,但是重点不在这里。事实上,它的速度太慢!让我们把程序改成“每步取模”的形式,然后加一个“计时器”,看看它到底有多慢。

#include<cstdio>
#include<ctime>
const int MOD = 1000000;
int main() {
	int n, s = 0;
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i) {
		int factorial = 1;
		for (int j = 1; j <= i; ++j)
			factorial = (factorial * j % MOD);
		s = (s + factorial) % MOD;
	}
	printf("%d\n", s);
	printf("Time used= %.2lf\n", (double)clock() / CLOCKS_PER_SEC);
	return 0;       //输出时间包含键盘输入的时间,建议用文件输入输出,后面章节介绍文件
}

这个程序真正的特别之处在于计时函数clock()的使用。该函数返回程序目前为止运行的时间。这样,在程序结束之前调用它,便可获得整个程序的运行时间。这个时间除以常数CLOCKS_PER_SEC之后得到的值以“秒”为单位。    

输入100000,按Enter键,系统迟迟不输出答案,原因在于程序中重复进行了多次阶乘运算,浪费了大量时间,具体优化方法请参考例1 。

也可以用数组来解决此类问题,代码如下:

#include <cstdio>
#include <ctime>
const int MOD = 1000000;
int factorials[100001];  // 存储已经计算过的阶乘
int main() {
	int n, s = 0;
	scanf("%d", &n);
	factorials[0] = 1;
	for (int i = 1; i <= n; ++i) {
		factorials[i] = (factorials[i - 1] * i) % MOD;  // 利用上一次的阶乘结果
		s = (s + factorials[i]) % MOD;
	}
	printf("%d\n", s);
	printf("Time used= %.2lf\n", (double)clock() / CLOCKS_PER_SEC);
	return 0;
}

优化后的代码主要有以下不同:

新增了一个数组 factorials 来存储已经计算过的阶乘值。

原始代码每次计算一个新的 i 的阶乘时,都要重新从 1 乘到 i ,而优化后的代码可以直接利用前一个 i - 1 的阶乘值乘以 i 得到当前 i 的阶乘值,避免了重复计算,大大提高了计算效率。

计算阶乘的方式改变。

原始代码通过嵌套的循环来计算阶乘,而优化代码通过数组存储和递推的方式计算阶乘。

总的来说,优化后的代码通过利用已计算的结果和避免重复计算,显著提高了程序在处理较大输入值时的性能。

🍁总结 

有不懂的地方可以si我,和我一起学习C++吧。

🍁备注

还没有下载DEV-C++的小伙伴们可以私我拿到免费安装包

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2041157.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

快速符合ISO26262产品认证——动力域L2监控方案精华分享

一、VCU应用层监控方案的ISO26262背景 “软件定义汽车”趋势下&#xff0c;更多汽车软件问题与消费者生命安全密切相关。而汽车行业ISO 26262《道路车辆功能安全》是一个国际安全标准&#xff0c;对安装在量产道路车辆上的电气、电子系统的功能安全进行了约束和规定&#xff0c…

C语言----约瑟夫环

约瑟夫环 实例说明&#xff1a; 本实例使用循环链表实现约瑟夫环。给定一组编号分别是4、7、5、9、3、2、6、1、8。报数初始值由用户输入&#xff0c;这里输入4&#xff0c;如图12.18所示&#xff0c;按照约瑟夫环原理打印输出队列。 实现过程&#xff1a; (1)在 VC6.0中创建…

整合springboot、mybatis-plus、做的电影的增删改查以及使用七牛云做图片的上传

一、建表 1.在数据库testdb库中新建一个movie表 2.表中的字段&#xff1a; mo_idmo_namemo_actormo_salespic_name 二、编写代码 1.第一步添加坐标 <properties><java.version>8</java.version></properties><dependencies><!--springspr…

一文带你快速了解——HAProxy负载均衡

一、HAProxy简介 1.1、什么是Haproxy HAProxy是法国开发者 威利塔罗(Willy Tarreau)在2000年使用C语言开发的一个开源软件是一款具备高并发(万级以上)、高性能的TCP和HTTP负载均衡器支持基于cookie的持久性&#xff0c;自动故障切换&#xff0c;支持正则表达式及web状态统计。…

用「画家流水线」的方式理解Transformer中间层

【导读】 Transformer架构层层堆叠&#xff0c;包含十几亿甚至几十亿个参数&#xff0c;这些层到底是如何工作的&#xff1f;当一个新奇的比喻——「画家流水线」&#xff0c;被用于类比并理解Transformer架构的中间层&#xff0c;情况突然变得明朗起来&#xff0c;并引出了一些…

基于 SpringCloud 分布式架构网上商城

目录 1绪论 4 1.1项目研究的背景 4 1.2开发意义 4 1.3课题研究现状 4 1.4项目研究内容与结构 5 2开发技术介绍 6 2.1Java技术 6 2.2 SpringCloud简介 6 2.3MySQL 介绍 7 2.4MySQL环境配置 7 2.5B/S架构 8 3系统分析 9 3.1可行性分析 9 3.1.1技术可行性 9 3.1.2经济可行性 9 3.…

C语言 ——— 结构体类型的声明、自引用、定义以及初始化

目录 结构体的声明 结构体的自引用 结构体的定义以及初始化 结构体的声明 结构体的概念&#xff1a; 结构体是一些值的集合&#xff0c;这些值称为成员变量&#xff0c;结构的每个成员可以是不同类型的变量 结构体的声明&#xff1a; 结构体声明的关键字&#xff1a;st…

【安卓】Service的基本用法

文章目录 Service简介启动和停止ServiceActivity和Service进行通信 Service简介 新建一个ServiceTest项目&#xff0c;然后右击com.example.servicetest→New→Service→Service。 每个Service中最常用到onCreate()、onStartCommand()和onDestroy()这3个方法其中onCreate()方法…

Tomcat 启动时出现 java.util.zip.ZipException: error in opening zip file

Tomcat启动 java.util.zip.ZipException: error in opening zip file 错误解决 今天做一个Tomcat的Demo时出现了一个小问题&#xff0c;也在网上查询了很多资料&#xff0c;遇到这个问题的人很少&#xff0c;基本上没有遇到过这种情况&#xff0c;在此记录一下。 报错信息 异…

5 C 语言常量的定义和分类、#define 和 const 定义常量的区别

目录 1 什么是常量 2 常量的分类 3 常量的定义 3.1 使用 #define 定义常量 3.1.1 介绍 3.1.2 定义格式 3.1.3 案例演示 3.1.4 执行时机 3.2 const 关键字 3.2.1 介绍 3.2.2 const 定义常量的格式 3.2.3 案例演示 3.2.4 执行时机 3.2.5 注意事项 4 #define 和 co…

Spring事务管理和事务传播机制详解

目录 一.简单理解事务 二.Spring中事务的实现 编程式事务 声明式事务 三.Transactional 详解 ▐ 异常回滚属性 rollbackFor ▐ 事务隔离级别 Isolation ▐ 事务的传播机制 propagation 一.简单理解事务 事务是⼀组操作的集合&#xff0c;是⼀个不可分割的操作。 事务会…

CORS解决前端跨域案例学习

跨域的概念不再解释&#xff0c;直接演示下出现跨域的情况&#xff1a; 前端代码&#xff08;index.html&#xff09;: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" conten…

comfyUI工作流也能变现了,“SD变现宝”把工作流转为小程序,重塑内容创作者的商业之路

前言 在数字化浪潮的推动下&#xff0c;内容创作行业正经历着前所未有的变革。如何在这个充满竞争与机遇的时代中脱颖而出&#xff0c;成为每个创作者必须面对的挑战。 SD变现宝&#xff0c;作为ComfyUI的最新插件&#xff0c;凭借其独特的功能与优势&#xff0c;为创作者们开…

赋能未来制造:三品图文档管理软件在大连船推图文档管理中的深度应用与成效

在信息化浪潮席卷全球的今天&#xff0c;企业的研发管理能力已经成为衡量其核心竞争力的重要标尺。三品软件与大连船用推进器有限公司携手合作&#xff0c;成功实施了EDM图文档协同管理系统项目&#xff0c;为企业在激烈的市场竞争中提供强有力的支持&#xff0c;确保其始终处于…

RCE绕过练习

一.了解eval与assert eval与assert区别_eval assert-CSDN博客https://blog.csdn.net/qq_53568983/article/details/129782507 看了php官方文档,assert中提到的许多名词不明白,转而搜索文章,这篇是解释的是最直白的 其中提到eval不是一个函数,是语言构造器,不能被可变函数调用…

Git代码管理规范

1. 简介 git 分支分为集成分支、功能分支和修复分支&#xff0c;分别命名为 develop、feature 和 hotfix&#xff0c;均为单数。不可使用 features、future、hotfixes、hotfixs 等错误名称。 master&#xff08;主分支&#xff0c;永远是可用的稳定版本&#xff0c;不能直接在…

数据中台运营与实战案例集锦(125页PPT)

方案简介&#xff1a; 本篇通过理论讲解与实战案例相结合的方式&#xff0c;深入剖析了数据中台的概念、架构、关键技术、实施路径以及运营策略。内容覆盖从数据中台规划到落地的全过程&#xff0c;包括数据治理、数据资产管理、数据服务化、数据分析与挖掘、以及如何通过数据…

PythonStudio 控件使用常用方式(二十六)TProgressBar

PythonStudio是一个极强的开发Python的IDE工具&#xff0c;官网地址是&#xff1a;https://glsite.com/ &#xff0c;在官网可以下载最新版的PythonStudio&#xff0c;同时&#xff0c;在使用PythonStudio时&#xff0c;它也能及时为用户升到最新版本。它使用的是Delphi的控件&…

MySQL:复杂查询(一)——聚合函数分组查询联合查询01

目录 1、聚合查询 1.1 聚合函数 1.1.1 COUNT() 1.1.2 SUM() 1.1.3 AVG() 1.1.4 MAX()&#xff0c;MIN() 1.2 分组查询 1.2.1 GROUP BY子句 1.2.1.1 round() 1.2.2 HAVING 1.2.3 示例 2、联合查询&#xff08;表连接查询&#xff09; 2.1 内连接 2.1.1 ①取相关表笛…

机器学习——全连接(MLP多层感知机)的理解

全连接即是矩阵乘&#xff0c;因此在transformer中获取QKV理论上是输入与QKV权重矩阵相乘&#xff0c;但实际操作则是使用全连接即nn.Linear()&#xff0c;注意这里的输入和输出都是二维的[batch,d_model]&#xff0c;即每个样本是一维的。