循环结构
概述和目标
介绍循环语句的应用场景,学会用“循环”思想解决实际问题;介绍java中的三种循环语句,掌握循环语句的结构,学会for语句、while语句及do-while的使用,掌握各循环语句的区别及实际开发中的取舍,理解嵌套循环的应用场景,掌握嵌套循环的使用,掌握break、continue、return语句在循环语句中的使用。
一、引言
重要提示:循环可以用于让一个程序重复地执行语句
汝有田舍翁,家资殷盛,而累世不识"之""乎".一岁,聘楚士训其子.楚士始训之搦管临朱.书一画训曰:一字;书二画,训曰:二字;
书三画,训曰:三字.其子辄欣欣然,掷笔归告其父,曰:儿得矣,儿得矣;可无烦先生,重费馆谷也,请谢去.其父喜,从之,具币谢遗楚士.
逾时,其父拟征召姻友万氏者饮,令子晨起治状,久之不成.父趣之,其子恚曰:"天下姓氏夥矣,奈何姓万!至晨起至今,才完五百画也."
呜呼!世之学者偶一解,辄自矜有得,贻类是也.
如果用循环这种结构来输出1万画还是很轻松的
二、循环的结构:
1、while循环
①初始化部分:只做一次初始化
while(②循环条件部分:如果循环条件满足(即该条件表达式为true),则执行循环体部分){
③循环体部分
④迭代部分:当循环体部分执行一次以后,执行迭代部分
}
案例1、我们前面的加法测试题无论对错只能回答一次,下面这个程序提示用户输入两个个位数相加的问题给出答案:让用户重复输入新的答案,直到答案正确为止。
1 import java.util.Scanner; 2 3 public class RepeatAdditionQuiz { 4 public static void main(String[] args) { 5 int number1 = (int)(Math.random() * 10); 6 int number2 = (int)(Math.random() * 10); 7 Scanner input = new Scanner(System.in); 8 System.out.println(number1 + " + " + number2 + " = ?"); 9 int answer = input.nextInt(); 10 while(number1 + number2 != answer) { 11 System.out.println("回答错误,请再试一次," + number1 + " + " + number2 + " = ?"); 12 answer = input.nextInt(); 13 } 14 input.close(); 15 } 16 }
案例2、猜数字,程序随机给出一个0至99(包括0和99)之间的数字,然后让你猜是什么数字。可以随便猜一个数字,游戏会提示太大还是太小,从而缩小结果范围。经过几次猜测与提示后,最终推出答案
import java.util.Random; import java.util.Scanner; public class GuessNumber { public static void main(String[] args) { //3.通过JDK提供给我们的随机类来生成一个随机整数 Random random = new Random(); int number = random.nextInt(100);//生成100以内的随机整数 System.out.println("请猜一个100以内的数字......"); Scanner input = new Scanner(System.in); int answer = -1; while(answer != number) { answer = input.nextInt(); if(answer == number) System.out.println("猜对了"); else if(answer > number) System.out.println("大了"); else System.out.println("小了"); } input.close(); } }
2、循环设计策略:
step1:确定需要重复的语句
step2:将这些语句放在一个循环体中,如下所示:
while(true){
语句组;
}
step3: 为循环继续条件编码,并为控制循环添加适合的语句。
while(循环继续条件){
语句组;
用于控制循环的附件语句;
}
示例:多个减法测试题
遵循循环设计策略,首先,需要确定重复的语句。这些语句包括:获取两个随机数,提示用户对两数做减法然后给试题打分。然后,将这些语句放在一个循环里。最后,增加一个循环控制变量和循环继续条件,然后执行循环5次。
import java.util.Scanner; public class SubstractionQuizLoop { public static void main(String[] args) { final int NUMBER_OF_QUESTION = 5; int count = 0; int correctCount = 0; Scanner input = new Scanner(System.in); long startTime = System.currentTimeMillis(); while(count < NUMBER_OF_QUESTION) { int number1 = (int)(Math.random() * 10); int number2 = (int)(Math.random() * 10); /** * 交换最大数作为被减数 */ if(number2 > number1) { int temp = number1; number1 = number2; number2 = temp; } System.out.println(number1 + " - " + number2 + " = "); int answer = input.nextInt(); if(answer == (number1 - number2)) { System.out.println("回答正确"); correctCount++; }else { System.out.println("回答错误"); } count++; } System.out.println("测试所化时间:" + ( (System.currentTimeMillis() - startTime)) / 1000); System.out.println("你回答正确数目:" + correctCount); System.out.println("你回答错误数目:" + (NUMBER_OF_QUESTION - correctCount)); input.close(); } }
使用标记值控制循环
读取和计算个数不确定的整数之和。
public class SentineValue { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.println("请输入你要计算求和的数,0退出"); int num = input.nextInt(); int sum = 0; while(num != 0) { sum += num; System.out.println("请输入你要计算求和的数,0退出"); num = input.nextInt(); } System.out.println(sum); input.close(); } }
输入和输出重定向(了解)
java SentineValue < input.txt > output.txt
案例:预测未来学费,假设电子科技大学今年的学费是10000元,每年以5%的速度进行增长,多少年后学费会翻倍
public class FutureTuition { public static void main(String[] args) { double tuition = 10000; int year = 0; while(tuition < 20000) { tuition = tuition + tuition * 0.05;// tuition * (1 + 0.05); year++; } System.out.println(year); } }
for循环
①初始化部分:只做一次初始化
②循环条件部分:如果循环条件满足(即该条件表达式为true),则执行循环体部分
③循环体部分
④迭代部分:当循环体部分执行一次以后,执行迭代部分
for(①;②;④){
③
}
for循环的执行顺序:①->②->③->④->②->③->④->②如果条件不满足,循环结束...
案例:使用穷举法求最大公约数(k(k=2,3,4,...)是否是num1和num2的公约数,直到k大于num1或num2)
public class GreatestCommonDivisor { public static void main(String[] args) { System.out.println("请输入两个整数:"); Scanner input = new Scanner(System.in); int num1 = input.nextInt(); int num2 = input.nextInt(); if(num1 < num2) { int temp = num1; num1 = num2; num2 = temp; } int gcd = 1; for(int k = 2;k <= num1 && k <= num2;k++) { if(num1 % k == 0 && num2 % k == 0) { gcd = k; } } System.out.println(num1 + "," + num2 + "的最大公约数为:" + gcd); input.close(); } }
显然,该算法的复杂度为O(num2),即O(n),如果不从1开始往上找,而是从num2往下找,这样会更高效,一旦找到这个数,该除数就是最大公约数。因此可以使用下面的循环改进
for(int k = num2; k >= 1; k--) { if(num1 % k == 0 && num2 % k == 0) { gcd = k; //找到就退出循环 break; } }
这个算法比前一个更高效,但是它在最坏情况下的时间复杂度依旧是O(n).
数字num2的除数不可能比num2/2大,因此,可以使用下面的循环进一步改进算法
for(int k = num2 / 2; k >= 1; k--) { if(num1 % k == 0 && num2 % k == 0) { gcd = k; //找到就退出循环 break; } }
但是,该算法是不正确的,因为num2有可能是num1的除数。这种情况必须考虑到。,正确的算法如下
public class GCD{ public static void main(String[] args) { System.out.println("请输入两个整数:"); Scanner input = new Scanner(System.in); int num1 = input.nextInt(); int num2 = input.nextInt(); if(num1 < num2) { int temp = num1; num1 = num2; num2 = temp; } int gcd = 1; if(num1 % num2 == 0) return num2; for(int k = num2 / 2; k >= 1; k--) { if(num1 % k == 0 && num2 % k == 0) { gcd = k; //找到就退出循环 break; } } System.out.println(num1 + "," + num2 + "的最大公约数为:" + gcd); input.close(); } }
打印出101年到2100年之间所有的闰年,每行打印10个,每个以制表符进行分割
public class PrintLeapYear { public static void main(String[] args) { for(int year = 101,line = 0;year <= 2100; year++) { if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) { System.out.print(year + "\t"); line++; } if(line == 10) { System.out.println(); line = 0; } } } }
do-while循环
①初始化部分:只做一次初始化
②循环条件部分:如果循环条件满足(即该条件表达式为true),则执行循环体部分
③循环体部分
④迭代部分:当循环体部分执行一次以后,执行迭代部分
do-while循环的组成
①
do{
③
④
}while(②);
public class DoWhileDemo { public static void main(String[] args) { int sum = 0; int num; Scanner input = new Scanner(System.in); do { num = input.nextInt(); sum += num; }while(num != 0); System.out.println(sum); input.close(); } }
while和do-while的区别:
while循环是先进行循环条件的判断,如果满足则执行循环体。
do-while循环是先执行一次do后语句块的内容(循环体和迭代部分),再执行循环条件的判断。
注意事项
1.理解“循环”思想是学习循环结构的前提,结合多个生活中的例子理清循环的组成部分,尤其是循环条件的作用;
2.讲解for循环、while循环和do-while循环时,先讲循环结构各组成部分的声明位置,再讲各组成部分的执行顺序;
3. 嵌套循环是本次课程的重点和难点,应多画图来分析每一次循环过程;
4. break、continue、return的区别以及标签的使用;
5. 同一语句块中break、continue、return后的语句不再执行。
三、嵌套循环:
循环体内包含循环。内层的循环作为外层循环的循环体。
外层循环:控制着行数
内层循环:控制着列数
public class MultiLoop { public static void main(String[] args) { for(int i = 1; i <= 9; i++) { for(int j = 1; j <= i;j++) { System.out.print(i + " * " + j + " = " + (i * j) + "\t"); } System.out.println(); } } }
四、break、continue、return的使用
1.break:结束(跳出)当前循环,不再进入下一次循环。注意:“当前”指的是break所在的循环。
了解“标记”的使用:1)用于给break、continue指明要结束的循环。
2)只能用在循环语句前面
3)标记的命名遵循标识符的命名规则和规范
示例:判断回文数(课堂练习)
import java.util.Scanner; /** * 判断一个字符串是否是回文 * */ public class Palindrome { /** * 从前往后以及从后往前都是一样的,它就是一个回文串,比如“1001”,“dad”,“mom” * 解决方案 * 判断字符串的第一个字符(“1001“.charAt(0))和最后一个字符(“1001”.charAt(“1001”.length() - 1)),如果相等 * 继续判断第二个字符及倒数第二个字符是否相等,这个过程一直持续找到不匹配,或者字符串中的每个字符都进行判断 * @param args */ public static void main(String[] args) { System.out.println("请输入一个字符串:"); Scanner input = new Scanner(System.in); String str = input.nextLine(); int low = 0; int high = str.length() - 1; boolean isPalindrome = true; while(low < high) { if(str.charAt(low) != str.charAt(high)) { isPalindrome = false; break; } low++; high--; } if(isPalindrome)System.out.println(str + "是一个回文串"); else System.out.println(str + "不是一个回文串"); input.close(); } }
示例:显示素数(课堂练习)
/** * 显示前50个素数,每行显示10个 * 素数:大于1的整数,只能被1和它自身整除的数即是素数 * 1.判断给定的一个数十不是素数 * 2.number=2,3,4,5,,,, * 3.统计素数个数 * 4.打印 * @author Adan * 测试一个数是不是一个素数: * 检测这个数能否被2,3,4一直到number/2整除,如果能被任意一个整除,就不是素数,break * */ public class PrimeNumber { public static void main(String[] args) { final int NUMBER_OF_PRIMES = 50; final int NUMBER_OF_LINES = 10; int count = 0;//定义一个计数器,统计素数的个数 int number = 2; while(count < NUMBER_OF_PRIMES) { boolean isPrime = true; //判断number是不是一个素数 for(int divisor = 2; divisor <= number / 2; divisor++) { if(number % divisor == 0) { isPrime = false; break; } } if(isPrime) { count++; if(count % NUMBER_OF_LINES == 0) System.out.println(number); else System.out.print( number+ " "); } number++; } } }
2.continue的用法:跳过所在(指定)循环的当次循环,进入下一次循环。
public class ContinueDemo { public static void main(String[] args) { for(int i = 1; i <= 100; i++) { if(i % 2 != 0) continue;//结束本次循环,判断下次循环条件,继续下一次循环 System.out.print(i + " "); } } }
注意:当发生跳过或结束循环时,break、continue后的语句不再执行
3.return的用法(后续):
1)当return用在方法里,表示将return 语句中return后的值返回给方法的调用者(了解),然后方法结束。因此,return语句后不能再跟着其他语句
2)return用在循环里,会终止循环,并且结束return所在的方法。因此后面的语句不执行。
作业
1.求1至1000之间满足“用3除余2;用5除余3;用7除余2”的数,且一行只打印5个数
2.求1-3+5-7+ …… -99+101的值
3.打印出所有的“水仙花数”,所谓“水仙花数”是指一个三位数,其各位数字立方和等于该数本身
4.输入两个正整数m和n,求其最大公约数和最小公倍数
5.百元百鸡问题:公鸡5元一只,母鸡3元一只,3只小鸡1元,如果用100元钱,买100只鸡,不佘不欠,可以买公鸡,母鸡,小鸡,各多少只。
6.编写一个Java应用程序,用循环结构打印如下的数值列表:
N 10*N 100*N 1000*N
1 10 100 1000
2 20 200 2000
3 30 300 3000
4 40 400 4000
5 50 500 5000
7.打印2到10000的所有素数,每行显示8个素数
8.3000米长的绳子,每天减一半,问,需要多少天,绳子会小于5米?
9.显示从101到2100期间所有的闰年,每行显示10个,之间用制表符分割
10.猴子吃桃问题。猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第十天早上在想吃时,就只剩一个桃子了。求第一天共摘了多少个桃子?
11.养老无忧计划:以目前的生活水平想要无忧养老需要存够600万养老金,假设你每年可以存N万,年利率为3%,问需要做牛做马多少年?
12.鸡兔同笼:今有雉(鸡)兔同笼,上有三十五头,下有九十四足。问雉兔各几何。
13.有5个人坐在一起,问第五个人多少岁?他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。问第三个人,又说比第2人大两岁。问第2个人,说比第一个人大两岁。最后问第一个人,他说是10岁。请问第五个人多大?
14.有1、2、3、4四个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?
15.一个数恰好等于它的因子之和,这个数就被称为“完数”。例如,6的因子为1、2、3,而6=1+2+3,因此6是“完数”。编程找出1~n之内的所有完数。
16.有一对兔子,从出生第三个月起每个月都生一对兔子,小兔子长到第三个月后,每个月又生一对兔子,假如兔子都不死,每个月的兔子总数。
17.一球从100米高度自由落下,每次落地后反跳回原高度的一半;再落下,求它在 第10次落地时,共经过多少米?第10次反弹多高?
18.啤酒瓶。买了100瓶啤酒,每三个空瓶可以兑换一瓶啤酒,问最多可以喝多少瓶啤酒
19.打印下列图形(方框忽略)
1.
2.
3.
4.
5.
6.
20.验收手机号码是否输入正确(1、 必须是11位数字;2、 前三位必须是130-139,158-159,186)
21、验收用户名是否输入正确(不可以用正则表达式),要求:
1、 必须是数字、大写字母、小写字母、下划线中的三种组成
2、 首字母必须是字母或下划线开头
3、 字符长度4-10
面试常见问题
1. 什么时候用for循环,什么时候用while循环
2. while循环和do-while循环的区别
3. break、continue、return的区别
验收手机号码是否输入正确