Java语言程序设计教程 第3章 程序流程控制 \uf070 3.1 分支结构 \uf070 3.2 循环结构 \uf070 3.3 程序跳转 \uf070 3.4 常用的程序设计方法 3.1 分支结构 常见的程序流程控制结构有顺序结构、分支结构和循环结构。 程序中最基本的结构是顺序结构 , 即大部分程序是按顺序从上往下执行的 。 分支结构用于在顺序结构中根据不同的条件提供了程序的分支 。 循环结构一般用于重复某段需要不断重复执行的代码 。 如下图所示: 语句1语句2 顺序结构语句块1 语句块2布尔表达式truefalse分支结构布尔表达式true语句块1循环结构程序的三种基本结构 分支结构也称为选择结构或判断结构,是通过判断给定的条件成立与否决定执行分支结构中包含的语句子句,分支结构有三种,if语句,if-else 语句和switch 语句。 3.1 分支结构——if语句 if 语句的语法格式为: if ( 布尔表达式) { 语句块; } if 语句根据条件来控制程序流程,条件用布尔表达式给出,当布尔表达式取值为true 时,执行语句块。这种分支语句叫单分支语句。 例如: if(score<60 ){ System.out.println(“ 不及格哦! 继续加油!”); } 3.1 分支结构——if-else语句 1. 双分支语句 if-else 语句为简单的双分支语句,布尔表达式的值为true 则执行if 语句块1 ,为false 则执行else 语句块2 。语法结构为: if ( 布尔表达式) { 语句块1 ;} else {语句块2 ;} 例如: if (score <60 ){ System.out.println(“ 不及格,下次努力哦!”); } else{ System.out.println(“ 恭喜通过考试!”); } 2. 多分支语句 嵌套的 if- - else 语句构成多分支语句,语法结构为: if ( 布尔表达式 1) { 语句块1 1 ; } else if( 布尔表达式 2) { 语句块2 2 ; } else if( 布尔表达式 3){ 语句块3 3 ; …… } else if( 布尔表达式 n){ 语句块n n ; else { 语句块 n+1 ;} } } 执行过程说明如下: (1 1 )首先判断表达式1 1 ,如果其值为 true ,则执行语句块1 1 ,然后结束 if 语句。 (2 2 )如果表达式1 1 的值为 false ,则判断表达式2 2 ,如果其值为 true ,则执行语句块2 2 ,然后结束 if 语句。 (3 3 )如果表达式2 2 的值为 false ,再继续往下判断其他表达式的值。 (4 4 )依次类推,如果所有表达式的值都为 false ,则执行语句块 n+1 。 例如: if (score < 60 ){ System.out.println(“ 下次努力哦!”);} else if(score<80){ System.out.println(“ 恭喜你通过考试!”);} else{ System.out.println(“ 你考的很棒!”); } 3.1 分支结构——switch语句 switch 语句允许程序员更多情况下选择不同的程序逻辑,当情况发生时,按照事先准备好的方法执行。switch 语句首先计算表达式的值,如果表达式的值和某个case 后面得常量值相同,就执行该case 里的语句块,知道遇到break 语句为止。若没有任何常量值与表达式的值相同,则执行default 后面的语句块。 switch语句的语法是: switch (表达式){ case 表达式值1: 语句块1; break; case表达式值2: 语句块2; break; case表达式值3: 语句块3; break; …… default: 语句块n; } switch 语句执行的流程 表达式或变量值1语句块1值2语句块2值3语句块3值n语句块nDefault语句块1......switch 语句执行流程图 实例:通过switch语句实现成绩档次的划分。 import java.util.*; public class Ex3_4 { public static void main(String args[ ]) { float score; Scanner in=new Scanner(System.in); System.out.println("请输入一个数字 :"); score=in.nextFloat(); switch ((int)score/10) { case 10: case 9: System.out.println("成绩为优秀"); break; case 8: System.out.println("成绩为良好"); break; case 7: System.out.println("成绩为中等"); break; case 6: System.out.println("成绩为及格"); break; default: System.out.println("成绩不及格"); break; } } } 循环语句使语句或语句块的执行得以重复进行。Java 编程语言支持三种循环构造类型:while, 和do-while 和for 循环。 3.2 循环结构 布尔表达式true循环体falsewhile语句布尔表达式true循环体falsedo-while语句表达式1布尔表达式2true循环体表达式3falsefor语句循环语句执行流程图 while 语句是Java 最基本的循环语句。while 循环语句的执行流程是先判断while 语句中的布尔表达式的值,如果是true ,则执行循环体语句,然后重新验证表达式的值,进入下一轮循环,一直到表达式的值为假时退出循环。如果布尔表达式的值是false ,则不执行循环体,直接退出循环执行后面的程序语句。while 语句的句法为: while ( 布尔表达式) { 语句或语句块; } 3.2 循环结构——while语句 在循环体中应该有使循环趋于结束的语句,否则循环将永远进行,导致死循环。 while 括号中的表达式必须是布尔型,表示循环执行的条件,循环体内可以是一条语句,也可以是语句块,只有单个语句时大括号可以省略,另外循环体可以是空体。 【 例 】 用while 语句求1-100 之和。 public class Ex3_5{ public static void main(String args[ ]) { int n=1,sum=0; while(n<=100) {sum+=n; n++;} System.out.println ("sum="+sum); } } do-while 语句和while 语句非常相似,不同之处是while 语句先判断后执行,而do-while 语句先执行一次再判断,循环体至少会被执行一次。所有通常称while 语句为“当型”循环,而do-while 语句称为“直到型”循环。do-while 循环总是先执行循环体,然后再计算布尔表达式。如果表达式为真,则循环继续,进入下一次循环。否则循环结束。do-while 语句的语法格式是: do { 语句或语句块; }while ( 布尔表达式) 3.2 循环结构——do-while语句 【 例 】 用do-while 语句求1-100 之和。 public class Ex3_6{ public static void main(String args[ ]) { int n=1,sum=0; do {sum+=n; n++; }while(n<=100) System.out.println("sum="+sum); } } for 语句的语法是: for (表达式1; 表达式2; 表达式3 ) { 语句或语句块; } for 语句的3 个表达式之间用分号分隔,表达式1 给出循环变量初值,表达式2 给出循环满足的条件,结果为布尔型,表达式3 给出步长,即循环变量的变化规律,递增或递减。循环体是大括号中的语句或语句块。 for 循环的执行过程是:先执行表达式1 ,为循环变量赋初值,在整个循环过程中只执行一次语句1 。再判断表达式2 的循环条件,结果为true 时执行循环体,然后执行表达式3 ,改变循环变量得值,进入下一轮循环。若表达式2的值为false ,循环结束,程序执行for 语句后面得语句 3.2 循环结构——for语句 【 例 】 用for 循环语句求1-100 之和。 public class Ex3_7{ public static void main(String args[ ]) { int sum=0; for(int n=1;n<=100;n++) {sum+=n; } System.out.println("sum="+sum); } } for 语句中,表达式1 和表达式3 都是逗号表达式,表达式1 中可以声明变量用于for 循环的执行。例如这样是完全可以的,for(int i=1,j=1;i<=10;i++,j++) 。For 语句是先判断后执行,执行次数可以是0 次或多次,由表达式3 来决定。例如: for(int i=0;i<0;i++) // 循环次数是0 次 for(int i=0;i<=0;i++) // 循环次数是1 次 for(int i=5;i>=1;i--) // 循环次数是5 次 3.2 循环结构——语句嵌套 和其他编程语言一样,Java 允许循环嵌套。也就是,一个循环在另一个循环之内,前一个循环称为内循环,后者称为外循环。While 循环、do-while 循环和for 循环之间可以相互嵌套。对于循环的嵌套,外循环完全包含内循环,不能交叉,不能从循环体外转向循环体内,也不能从外循环转向内循环。另外在循环语句中也可以完整嵌套分支结构,在分支结构中也可以嵌套循环结构,来实现一些较为复杂的运算。 1. while 嵌套 while 循环可以嵌套,即在一个循环体内又包含了另一个完整的循环结构。 while (布尔表达式1 ){ [ 语句或语句块1 ;] while (布尔表达式2 ){ [ 语句或语句块2 ;] } [ 语句或语句块3 ;] } 2.do-while 循环嵌套 3. for 循环嵌套 4. 相互嵌套 for( ) { … while() { …} … } for( ) { … do { …} while(); … } do( ) { … for( ) { …} } while(); do { … while( ) { …} … } while(); while( ) { … do { …} while(); … } while( ) { … for( ) { …} … } 举例 【 例3.11 】 :有1 、2 、3 、4 个数字,能组成多少个互不相同且无重复数字的三位数?这些数字都是多少? public class Ex3_11 { public static void main(String[] args) { int i=1,j=1,k=1, m=0; System.out.println("满足条件的三位数分别是:"); while(i<=4) { for(j=1;j<=4;j++) for( k=1;k<=4;k++) if (i!=j && j!=k && i!=k) {m+=1; System.out.print(i*100+j*10+k+" "); if((m)%5==0) System.out.println(); } i++; } System.out.println(); System.out.println ("这样的三位数共有"+m+"个"); } } 【 例3.12 】 使用嵌套循环语句和分支语句打印输出九九乘法口诀表。 public class Ex3_12 { public static void main(String args[]){ System.out.println(" 九九乘法口诀表"); for(int i=1;i<=9;i++){ for(int j=1;j<=i;j++){ System.out.print(+j+"*"+i+"="+i*j); if(i*j<10) {System.out.print( " ");} else{System.out.print( " ");} } System.out.println(); } } } 3.3 程序跳转 Java 语言提供三种程序跳转语句:break 、continue 和return 语句。跳转语句用在控制流程转移语句中。 1 break 语句 break 关键字的意思是中断、打断。break流程控制是用来强行中断运行的程序语句或语句块,使得程序流程跳出该区块,继续运行后面的语句。Break 用于循环中,表示跳出break 所在的循环,哪个循环调用了break ,就跳出哪个循环;。break语句的语法格式为: break [ 标号] ; break 用在分支结构switch 中表示退出当前的switch 语句。switch 语句中默认的格式中,每个case 后面都有个break ,因此执行完case 中的语句后,就会退出switch 语句。如果某个case 后面没有break ,意味着执行完这个case 中的语句后,会按顺序执行后面所有case 和default 中的语句,直到遇到break 为止 【 例3.13 】 求1-100 的和,当和大于100 时退出。 public class Ex3_13{ public static void main(String args[ ]) { int sum=0; for(int i=1;i<=100;i++) {sum+=i; if(sum>100) break;} System.out.println("sum="+sum); } } 2 continue 语句 continue 关键字的意思是继续,添加分号则表示语句。continue 语句的语法格式为: continue [label] ; continue 语句只能用于循环结构,当不带标号时时提前结束本次循环,进入下一轮循环的运行中。对于while 和do-while 循环,不带标号得continue 语句使程序流程直接跳转到条件表达式的判断中,而对于for 语句,跳转到表达式3 中,修改步长后再进行条件表达式的判断。 【 例3.14 】 计算满足条件的偶数的和,当和超过100 时停止执行并输出满足条件的偶数和。 public class Ex3_14{ public static void main(String args[ ]) { int sum=0,i=0; do { i++; if(i%2!=0) continue; sum+=i; }while(sum<100); System.out.println("sum="+sum); } } 3 return 语句 Java 中的return 语句总是和方法有密切关系,return 语句总是用在方法中,有两个作用,一个是返回方法指定类型的值,一个是结束方法的执行。方法中不论有没有返回值类型,都可以带有return 语句。如果方法有返回值类型(即返回值类型不为void ),则必须带有返回相应类型值的return 语句,。如果方法中没有返回值(即返回值类型为void ),则方法中return 语句的后面不能加任何的变量,此时也可以没有return 语句。return 语句的语法格式为: return [ 返回值] ; public class Ex3_16 { public static void main(String[] args) { System.out.println("main()方法开始执行"); method( ); System.out.println("main()方法结束执行"); } public static void method(){ System.out.println("method()方法开始执行"); for(int i=0;i<5;i++){ if(i==3){ return; } System.out.println("i="+i); } System.out.println("method()方法结束执行"); } } 3.4 常用的程序设计方法 算法是为完成一项任务所应当遵循的规则,应该有精确的、无歧义的描述。程序设计中根据实际问题的不同,有很多已成熟的算法,这些算法充分使用流程控制语句,下面列举一些常用的方法。 3.4.1 枚举法 在程序设计中,经常需要根据给定的一组条件求满足条件的解,若问题的解可以用现有的公式,或者按照一定的规则规律求得,那么就可以很容易写出相应的程序代码。但是对于现实生活中的很多问题,都难以找到明确的公式或者规则,在这种情况下,可以使用枚举方法进行求解。 枚举法,也称之为穷举法,其基本思想是先依据题目给定的条件将所有可能解列举出来,然后用其余的条件对所有可能解逐一验证,验证是否是问题的解,删去不符合条件的解,剩下符合条件的解就是整个问题的解。 枚举算法问题举例说明如下: 【 例3.17 】 采用枚举法实现打印出100-999 之间所有的"水仙花数" ,所谓" 水仙花数" 是指一个三位数,其各位数字立方和等于该数本身。 对100 到999 的任意三位数m ,其个位、十位、百位上的数字,用x y z 表示,使用for 循环和if 语句实现。 public class Ex3_17 { public static void main(String[] args) { for (int m = 100; m <=999; m++) { int x = m%10; int y = m/10%10; int z = m/100; if(m==Math.pow(x,3) + Math.pow(y,3) + Math.pow(z,3)){ System.out.println("水仙花数m="+m); } } } } 【 例3.18 】 百钱买百鸡问题。有一个人有一百块钱,打算买一百只鸡。到市场一看,公鸡每只5 元, 母鸡每只3 元, 小鸡1 元买3 只, 编程实现什么样的买法,才能刚好用一百块钱买一百只鸡? 此题很显然是用枚举法,以三种鸡的个数为枚举对象(分别设为x,y,z ), 以三种鸡的总数(x+y+z )和买鸡用去的钱的总数(x*5+y*3+z/3) 为判定条件,穷举各种鸡的个数。 class ChickenBuy { static int x;// 可买公鸡的只数 static int y;// 可买母鸡的只数 static int z;// 可买小鸡的只数 public void buy(){ x=0; while(x<=19){ y=0; while(y<=33){ z=100-x-y; if(x*5+y*3+z/3==100&&z%3==0){ System.out.print(" 可买公鸡的只数:"+x+" "); System.out.print(" 可买母鸡的只数:"+y+" "); System.out.println(" 可买小鸡的只数:"+z); } y++; } x++; } } } public class Ex3_18 { public static void main(String[] args) { ChickenBuy chicken=new ChickenBuy(); chicken.buy();} } 【 例3.19 】 生活中的问题:某同学忘记QQ 密码了,你能帮着找回吗?他的密码是一个5 位数,67XX8 ,其中十位和百位上的数字不记得了,但他确定这个数能够被78 整除,也能被67 整除,设计算法求出该密码中的十位和百位。 此题使用枚举法,设十位和百位上的数字分别为x,y 。 public class Ex3_19 { public static void main(String[] args) { for(int y=0;y<=9;y++) {for(int x=0;x<=9;x++){ if((6*10000+7*1000+y*100+x*10+8)%78==0 &&(6*10000+7*1000+y*100+x*10+8)%67==0){ System.out.print("十位上的数字x="+x+", "); System.out.println("百位上的数字y="+y+".");} } } } } 2 递推法 递推是计算机数值计算中的一个重要算法,思路是通过数学推导,将复杂的运算化解为若干重复的简单运算,以充分发挥计算机擅长重复处理的特点。 递推,是指从已知的初始条件出发,依据某种递推关系,逐次退出所要求得各中间结果及最后结果。其中初始条件或是问题本身已经给定,或是通过对问题的分析与化简后确定。可分为顺推法和逆推法。 1. 顺推法,就是先找到递推关系式,然后从初始条件出发,一步一步地按递推关系式递推,直至求出最终结果。 2. 逆推法,就是在不知道初始条件的情况下,经某种递推关系而获知问题的解,再倒过来,推知它的初始条件。 【 例3.20 】 上楼梯问题,设有共有n 级楼梯,某人每步可走1 级,也可走2 级,也可走3 级,求从底层开始走完全部楼梯的走法共有多少种? 分析:当n=1 时, 走法x=1; 当n=2 时, 走法x=2; 当n=3 时, 走法x=4 (1 ,1 ,1 模式,1 ,2 模式,2 ,1 模式和3 模式); 依次顺推发现后续当层级增加一级时,走法时前三级的走法之和,问题由复杂变简单了。 import java.util.*; public class Ex3_20{ public static void main(String[] args) { int x=0,n,f1=1,f2=2,f3=4; Scanner in=new Scanner(System.in); System.out.println("请输入楼层的级数 :"); n=in.nextInt(); if(n==1)x=f1; else if(n==2) x=f2; else if (n==3) x=f3; for(int i=4;i<=n;i++) {x=f1+f2+f3; f1=f2; f2=f3; f3=x; } System.out.println("输入的楼层级数:n="+n); System.out.println("根据走法规则 ,得到的走法总数为:x="+x); } } 【 例3.21 】 猴子吃桃问题, 猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个;第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半又一个。到第10 天早上想再吃时,见只剩下一个桃子了。求猴子第一天共摘了多少桃子。 已经条件第10 天剩下一个桃子,隐含条件每一次前一天的桃子树等于后一天桃子树加1 的2 倍。采用逆向思维的方法,从后往前推,用逆推法求解。设x1 为当天的桃子,也即前一天剩下的桃子数,x2 为当天剩下的桃子数。 public class Ex3_21 { public static void main(String[] args) {int day=9, x1=0,x2=1; while(day>0) {x1=(x2+1)*2; x2=x1; day--; System.out.println("猴子第一天摘的桃子数量为:"+x1);} } 3 递归法 如果一个对象的描述中包含它本身,就称这个对象是递归的,这种用递归来描述的算法称为递归法。递归法通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解递归策略只需少量的程序就可以描述出解题过程所需要的多次重复计算,大大地减少了程序得代码量。一般来说,能使用递归解决的问题应该满足以下三个条件: 1. 需要解决的问题可以化为一个或多个子问题来求解,而这些子问题的求解方法与原来的问题完全相同,只是再规模上不同。 2. 递归调用的次数必须是有限次的。 3. 递归必须能终止,有结束递归的条件。 【 例3.22 】 使用递归算法求解n !。 根据数学知识0 !=1 ,1 !=1,n!=n*(n-1)*(n-2)*…*2*1=n(n-1)! 。通过键盘输入一个数,使用java.util.Scanner 类和方法来实现 import java.util.*; public class Ex3_22 { public static void main(String[] args) { int n; Scanner s = new Scanner(System.in); System.out.print( " 请输入一个整数: "); n = s.nextInt(); JieCheng a=new JieCheng(); System.out.println(n+"!="+a.cheng(n)); } } class JieCheng{ public long cheng(int n){ long i=0; if(n==0||n==1) i=1; else i=n*cheng(n-1); return i; } } 【 例3.23 】 兔子繁殖问题。如果有一对小兔,每一个月都生下一对小兔,而所生下的每一对小兔在出生后的第三个月也都生下一对小兔。那么,由一对兔子开始,12 个月时一共可以繁殖成多少对兔子? 这个问题是Fibonacci 问题,很容易找到规律,即除了第一个月和第二个月外,后面每个月份的兔子总对数恰好等于前面两个月份兔子总对数的和,用递归法来完成。 public class Ex3_24 { public static void main(String[] args) { Fibon fi=new Fibon(); System.out.println("12 个月时繁殖的兔子数为:"+fi.fibonacci(12)); } } class Fibon { public int fibonacci(int n){ if((n==1)||(n==2)) return 1; else return fibonacci(n-2)+fibonacci(n-1); } } 【 例3.24 】 有6 个人坐在一起,问第6 个人多少岁?他说比第5 个人大2 岁, 问第五个人多少岁?他说比第4 个人大2岁, 问第4 个人岁数,他说比第3 个人大2 岁, 问第三个人,又说比第2 人大两岁, 问第2 个人,说比第1 个人大2 岁, 最后问第1 个人,他说是18 岁。请问第6 个人多大? public class Ex3_24 { static int getAge(int n){ if (n==1) return 18; else return 2 + getAge(n-1); } public static void main(String[] args) { System.out.println("第6个的年龄为:"+getAge(6)); } } 4 简单图形的输出 使用程序流程控制语句和一些简单的算法设计,就能设计出一些简单的图形,下面举例说明 【 例3.25 】 使用“* ”号打印输出菱形图案。 public class Ex3_25{ public static void main(String args[]){ int i,j,k; for(i=1;i<=4;i++) // 先打印上边的四行 { for(j=1;j<=4-i;j++) // 控制要打印的空格数量 System.out.print(" "); for(k=1;k<=2*i-1;k++) // 控制要打印的星号数 System.out.print("*"); System.out.println("\n"); } for(i=1;i<=3;i++) { for(j=1;j<=i;j++) // 控制要打印的空格数 System.out.print(" "); for(k=1;k<=7-2*i;k++) // 控制要打印的星号数 System.out.print("*"); System.out.println("\n"); } } } 程序运行结果为: * *** ***** ******* ***** *** * 【 例3.26 】 打印输出杨辉三角形 public class Ex3_26 { public static void main(String[] args) { int[][]a=new int[10][10]; for(int i=0;i<10;i++){ a[i][i]=1; a[i][0]=1; } for(int i=2;i<10;i++){ for(int j=1;jmax){ System.out.println(" 太大哦, 猜了"+(i+1)+" 次!"); } if(j==max){ System.out.println(" 猜对了, 这个数字是"+j+", 猜了"+(i+1)+" 次!"); break; } i++; } while(i<10); System.out.println(" 谢谢使用"); } } 小结 本章介绍了常见程序流程控制语句,包括顺序结构、分支结构、循环结构和程序跳转语句等,也介绍了几种程序控制的算法和这些程序流程控制语句的应用,最后将通过一些实例,为读者讲述如何在程序设计中设计好程序流程控制。 本章重点是理解程序控制的概念,运用分支语句,使用if,switch 来控制程序的不同执行路径,掌握for 、while 和do 句型结构控制程序的循环执行,理解并能应用break 和continue 调整程序中的流程控制结构,理解分支和循环的影响语句范围等。 本章难点是循环结构条件的判断,循环执行过程以及循环终止的判断,选择的嵌套及多重循环结构的应用。 本章习题 1. 下面不属于java 条件分支语句结构的是 ( ) 。 A.if 结构 B. if -else 结构 C.if -else if 结构 D. if -else else 结构 2. 分支语句switch (表达式){}中,表达式不可以返回哪种类型的值( ) 。 A. 整型 B. 实型 C. 布尔型 D. 字符型 3. 关于while 和do -while 循环,下列说法正确的是( ) 。 A. 两种循环除了格式不通外,功能完全相同 B. 与while 语句不通的是,do -while 语句的循环至少执行一次 C. do-while 语句首先计算终止条件,当条件满足时,才去执行循环体中的语句 D. 以上都不对。 4. 在一个循环中使用break ,continue 和return 有什么不同? 5. 程序流程控制有哪几种?他们分别对应Java 中哪些语句 6. 使用for 循环语句求出1~100 之间的质数。 7. 从键盘输入一个正整数,按数字的相反顺序输出。 8. 使用不同得程序流程控制语句求解八皇后问题。