版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1第四章Java循环语句学习目标·使用while循环编写“重复执行某些语句”的程序·实训一:编写程序GuessNumber·遵循循环设计策略来开发循环·实训二:编写程序SubstractionQuizLoop·使用标志值控制循环·使用输入重定向以获取大量输入数据·使用do-while语句编写循环·使用使用for语句编写循环·了解三种类型循环语句的相似处和不同点·编写嵌套循环·从多种例子中学习循环·使用break和continue来实现程序的控制·使用确定对话框
控制循环24.1引言如果你想打印一个字符串
“WelcometoJava!”100次,就需要把下面的语句重复写上100遍!
System.out.println("WelcometoJava!"); System.out.println("WelcometoJava!"); ...... System.out.println("WelcometoJava!");Java提供了一种称为循环的结构,用来控制一个语句块重复执行的次数。下面的代码就是使用循环语句
来告诉计算机打印上面这个字符串100次:
intcount=0; while(count<100) { System.out.println("WelcometoJava!"); count++; }其中的语句将被重复执行100遍!34.2
while循环while语句的语法格式是:while(布尔表达式){
语句块//“循环体”
}while语句的执行流程如图4-1所示。•循环结构中包含的语句块称为循环体(即需要重复执行的操作序列);•循环体的每一次执行称为一次循环迭代;•每个循环结构都需要一个循环的继续条件,它是一个布尔表达式;•每次循环迭代前,总是先计算这个循环继续条件以决定是否执行循环体。若为true,则执行循环体;否则,终止整个循环并将程序的控制转移到while语句之后的下一条语句。图4-1while语句的流程说明truefalse布尔表达式语句块下一条语句4图4-2
打印字符串100次的流程说明truefalsecount<100System.out.println("WelcometoJava");count++;下一条语句count=0提示当事先确切知道循环次数时,可以使用一个变量(例如,count)来对执行次数进行计数。这种类型的循环称为“计数器控制的循环”。5
下面是另外一个例子,有助于理解循环是如何工作的: intsum=0,i=1; while(i<100){ sum=sum+i; i++; } System.out.println("sum="+sum);
如果循环被错误的写成如下所示,那会出现什么情况? intsum=0,i=1; while(i<100){ sum=sum+i; } System.out.println("sum="+sum);警告必须确保循环条件最终可以变为false,以便循环能够结束。一个常见的循环设计错误是无限循环(也叫做“死循环”)。也就是说,由于循环条件的不当而使循环永远不可能结束。其中变量sum被称为“累加器”每次的重复都是从旧值的基础上“迭代”出新值,并由新值替代旧值。6
另外,程序员经常会犯的错误,就是使循环多迭代一次或少迭代一次,这种情况称为“出一错误”(off-byoneerror)。
例如,下面的循环会将字符串“WelcometoJava!”打印101次: intcount=0; while(count<=100){ System.out.println("WelcometoJava!"); count++; }
这个错误出在什么地方呢?7注意1)只有当循环体内只包含一条语句或不包含语句时,循环体的花括号{}才可以省略;2)当循环体不包含语句时,必须留一个分号“;”,以表示“空操作”或叫做“空语句”。System.out.print("开始计时......");finalintGAP=10;longstartTime=System.currentTimeMillis()/1000;while((System.currentTimeMillis()/1000-startTime)<GAP);System.out.println(GAP+"秒钟时间到!");inti=0;while(i<100)System.out.println(++i);84.2.1
实例:猜数字下面是该程序要求的一次运行示例:
请你猜一个[0~100]的魔数请输入你的猜测:50↙你的猜测大了!请输入你的猜测:25↙你的猜测大了!请输入你的猜测:12↙你的猜测大了!请输入你的猜测:6↙你的猜测小了!请输入你的猜测:9↙恭喜你猜对了!这个数是9.根据我们已有的经验,该程序首先需要产生一个0~100的随机数(魔数),然后提示用户输入一个猜测数,接着便可以将这个猜测数与随机数进行比较了。
不要急于编程!编码前的思考是非常重要的!尤其是涉及循环的程序设计。切记:一次增加一个步骤地“逐步编码”是一个很好的习惯.9提示如果不知道如何立即编写循环,可以编写循环只执行一次的代码,然后规划如何在循环中重复执行这些代码——这是一种很好的办法。10下面我们先为该程序打一个初稿——循环只执行一次的代码://源程序清单4-1(初稿)GuessNumber.javaimportjava.util.Scanner;publicclassGuessNumber{publicstaticvoidmain(String[]args){
//产生一个魔数(随机数)intnumber=(int)(Math.random()*101);Scannerinput=newScanner(System.in);System.out.println("请你猜一个0~100的魔数");System.out.print("请你输入一个猜测数:");intguess=input.nextInt(); //读入用户输入的猜测数if(guess==number) System.out.println("恭喜你猜对了!这个数是" +number);elseif(guess>number) System.out.println("你的猜测大了!");else System.out.println("你的猜测小了!");
}}while(true)}
while(guess!=number)
}虽然这个循环可以重复提示用户输入猜测数并进行比较,但是它永远都不会结束!正确的做法应该是当guess与number匹配时,该循环就应该结束。所以应该改写循环继续条件.11下面给出该程序的完整代码://源程序清单4-1GuessNumber.javaimportjava.util.Scanner;publicclassGuessNumber{publicstaticvoidmain(String[]args){intnumber=(int)(Math.random()*101); Scannerinput=newScanner(System.in); System.out.println("请你猜一个0~100的魔数");
intguess=-1;//初始化guess while(guess!=number){ System.out.print("请你输入一个猜测数:"); guess=input.nextInt(); if(guess==number) System.out.println("恭喜你猜对了!这个数是" +number); elseif(guess>number) System.out.println("你的猜测大了!"); else System.out.println("你的猜测小了!"); }//循环结束}}注意这里的guess必须进行初始化,否则会出现编译错误。这里将它初始化为-1。将它初始化为0~100之间的数,就会影响程序的正确性。因为,它很可能就是要猜测的数。124.2.2
循环设计策略
编写循环时,应该考虑如下四个步骤:i)确定需要重复执行的语句;ii)将这些语句放在一个循环中。iii)编写循环条件,并为控制循环添加适当的语句。intcount=0;while(){System.out.println("WelcometoJava!");count++;}iv)为循环变量(如,count)选择适当的初始值。以免“出一错误”。count<100
intsum=0,i=1;while(){sum=sum+i;i++;}//sum=1+2+...+99累加器变量sum初始化i<100
循环控制变量i初始化134.2.3
实例:高级数学学习工具
程序清单3-4中的数学减法学习工具只能产生一道题目。现在我们使用循环来重复产生题目。如何编写能产生5道题目的代码呢?遵循循环设计策略:i)确定需要重复的语句:获取两个随机数,提示用户对两数做减法,然后打分;ii)将这些语句放入一个循环里。iii)增加一个循环变量和循环条件,并为控制循环添加适当的语句。下面的程序清单4-2给出的程序可以产生5道题目,在学生回答完所有5道题目后,报告回答正确的题数。这个程序最后还显示该测试所花的时间,并列出所有题目的回答情况。14//源程序清单4-2SubstractionQuizLoop.javaimportjava.util.Scanner;publicclassSubstractionQuizLoop{publicstaticvoidmain(String[]args){finalintNUMBER_OF_QUESTIONS=5;//声明问题数量intcorrectCount=0; //“回答正确”计数器初始化intcount=0;//“问题数量”计数器初始化longstartTime=System.currentTimeMillis();//开始时间Stringoutput="";//“回答问题的情况汇总”字符串初始化Scannerinput=newScanner(System.in);while(count<NUMBER_OF_QUESTIONS){ intnumber1=(int)(Math.random()*10);
intnumber2=(int)(Math.random()*10); //确保number1不小于number2 if(number1<number2){ inttemp=number1; number1=number2; number2=temp; } 15 //出题 System.out.print(number1+"-"+number2+"=?"); intanswer=input.nextInt();//读入键盘输入的答案 if(number1-number2==answer){//显示评语 System.out.println("正确"); correctCount++; } else System.out.println("你的回答是错误的。\n" +number1+"-"+number2 +"应该是"+(number1-number2)); count++;//问题数量加1 output+="\n"+number1+"-"+number2+"="+answer +(number1-number2==answer)?"正确!":"错误!";}//循环结束(学生测试结束)//产生“结束”时间、测试用时和显示汇总信息
longendTime=System.currentTimeMillis();longtestTime=endTime-startTime;//计算“测试用时”System.out.println("正确的次数为:"+correctCount+"\n用时为:"+testTime/1000+"秒\n情况汇总:\n"+output);}}16
下面我们来编写这样一个程序:读取和计算个数不确定的整数之和。当读取的数为
0
时,表示输入结束。现在需要解决的问题有:1)对于每次输入的整数是否都需要声明新变量?不需要!只需要使用一个变量(例如,data)来存储输入的值。2)如何求它们的和?使用累加器。(类似
sum=sum+data
来计算1+2+3+...+99)该程序的算法描述如下:(i)输入一个整数给data;(ii)如果data不为0,则执行(iii);否则执行(v);(iii)sum=sum+data;(iv)再输入一个整数给data;然后转去执行(ii);(v)输出变量sum的值。4.2.4
使用标志位控制循环另一种控制循环的常用技术是在读取和处理一个集合的数据时指派一个特殊值。这个特殊的输入值也称为结束标志——表明循环的结束。这种使用标志值来控制的循环称为标志值控制的循环。17data=input.nextInt();while(data!=0){sum+=data;data=input.nextInt();}System.out.println(sum);该程序的算法描述如下:(i)输入一个整数给
data;(ii)如果data不为0,则执行(iii);
否则执行(v);(iii)sum=sum+data;(iv)
再输入一个整数给data;然后转去执行(ii);(v)
输出变量sum的值。truefalsedata!=0sum+=data读入data读入data输出sum18//源程序清单4-3SentinelValue.javaimportjava.util.Scanner;publicclassSentinelValue{publicstaticvoidmain(String[]args){ Scannerinput=newScanner(System.in); //提示用户输入System.out.print("请输入若干个整数(0表示输入结束):"); intdata=input.nextInt();//读入用户输入的第一个整数 //以下循环结构循环读入用户输入的整数,直到遇0为止。 intsum=0;//累加器初始化 while(data!=0){ sum+=data; //读入用户输入的下一个整数 System.out.print("请输入一个整数(0表示输入结束):"); data=input.nextInt(); } System.out.println("它们的和是:"+sum);}}19警告在循环控制中,不要使用浮点数来比较值是否相等。因为浮点数都是某些值的近似值,使用它们可能导致不精确的循环次数和不准确的结果。请观察下面计算1+0.9+0.8+0.7+....+0.1的代码: doublesum=0,item=1; while(
item!=0){ sum+=item; item=item-0.1; } System.out.println("它们的和是:"+sum);因为浮点数在算术上是近似值,所以,不能确保item会变成真正的0。从表面上看,这个循环似乎没问题,但实际上它是一个无限循环!20我们可以改用下面方法来解决: doublesum=0,item=1; while(
Math.abs(item)>1e-6){ sum+=item; item=item-0.1; } System.out.println("它们的和是:"+sum);21另外,如果想要判断两个浮点数x1、x2是否相等,那么,你就应该使用下面的方法来解决:
while(Math.abs(x1-x2)<1e-6){...}而不能使用下面的代码: while(x1==x2){...}22*4.2.5
输入输出重定向如果你想避免在程序运行过程中输入大量的数据,可以将这些数据用空格隔开,保存在一个文本文件(例如,input.txt)中,然后使用下面这个命令来运行这个程序: javaSentinelValue<input.txt这个命令称为输入重定向。它会告诉程序中的读入方法“input.nextInt();”从文件input.txt中去读入数据,而不是让用户在运行时从键盘输入数据。假设input.txt文件的内容是:23456789122332234567899212343531240那么,你用上面这个命令来运行这个程序的话,将得到sum的值为518。
类似地,输出重定向可以将程序本来在屏幕上显示的结果发送到文件中去。输出重定向的命令是: javaSentinelValue>output.txt可以同一命令中同时使用输入输出重定向。例如,下面的命令会从文件input.txt中读取数据,并将输出结果发送到文件output.txt中:javaSentinelValue<input.txt>output.txt
请使用这个命令来运行这个程序,查看一下output.txt中的内容是什么。234.3
do-while循环
do-while语句是while语句的变体。其语法格式是:
do{ 语句块
}while(布尔表达式);它的执行流程如图4-3所示:首先执行循环体;然后计算并判断循环条件:如果为true,则重复执行循环体;否则,终止循环,转去执行下一条语句。
do-while语句与while语句的差别在于:判断循环条件和执行循环体的顺序不同。图4-3do-while流程说明下一条语句truefalse布尔表达式语句块24
do-while语句和while语句具有相同的表达能力。有时候,选择其中一个会比另一个更方便。例如,可以使用do-while循环来改写程序清单4-3中的while循环。如下面的程序清单4-4所示。//源程序清单4-4TestDoWhile.javaimportjava.util.Scanner;publicclassTestDoWhile{//读取并计算个数不确定的整数之和。
publicstaticvoidmain(String[]args){ Scannerinput=newScanner(System.in); intdata,sum=0; do{//提示用户输入 System.out.print("请输入一个整数(0表示输入结束):"); data=input.nextInt(); sum+=data; }while(data!=0); System.out.println("它们的和是:"+sum);}}25提示
如果循环中的语句至少需要执行一次,那么,建议使用do-while循环。因为,如果使用while循环,这些语句就必须在循环前和循环内都出现。(请对照程序清单4-3和程序清单4-4)26do-while语句应用举例求解 利用牛顿迭代法求平方根的迭代公式为:当|xn+1‒
xn
|<ε时,xn+1即为解的近似值。(提示:x0可以是任意猜测值。为方便起见,可以取a的值。)算法描述如下:(i) x0=a;(ii) x1=x0;(iii) x0=(x1+a/x1)/2;(iv) |x0‒x1|<10-6?是,转至(v);否则转至(ii);(v) x0(或x1)就是最后的解。。其中a是常数(a≠0)27//源程序清单3-2SolvingEquationsWithIterative.javaimportjava.util.Scanner;publicclassSolvingEquationsWithIterative{publicstaticvoidmain(String[]args){ Scannerinput=newScanner(System.in); System.out.print("请输入一个数:"); doublea,x0,x1; a=input.nextDouble(); x0=a; do{ x1=x0; x0=(x1+a/x1)/2; }while(Math.abs(x1-x0)>1E-8); System.out.println(a+"的平方根是:"+x0);}}(i) x0=a;(ii) x1=x0;(iii) x0=(x1+a/x1)/2;(iv) |x0‒x1|<10-6?是,转至(v);否则转至(ii);(v) x0(或x1)就是最后的解。28“迭代法”也叫做“递推法”,其基本思想是:把一个复杂的计算过程转化为简单过程的多次重复,每次重复都从旧值的基础上递推出新值,并由新值替代旧值。(最简单的例子就是“累加器”)294.4
for循环经常会用到下面的通用形式来编写循环:
i=初值;
while(i<终值){
......//循环体
i++;
//循环变量加1
}可以使用for语句来简化这个循环:
for(i=初值;i<终值;i++){
......//循环体 }
for语句的语法格式如下所示: for(初始操作;循环条件;每次迭代后的操作
){ ......//循环体 }它的执行流程如右边图所示。truefalse循环条件语句块下一条语句初始操作每次迭代后的操作30例如,下面的for循环打印字符串100次:inti;for(i=0;i<100;i++){System.out.print("Hello!");}其流程图如右图所示。循环控制变量可以在for语句中声明和初始化:for(inti=0;i<100;i++){System.out.print("Hello!");}如果像这个例子一样,循环体只有一条语句,那么,花括号也是可以省略的。truefalsei<100"Hello!"i=0i++提示如果循环控制变量只在for循环内使用而不在其他地方使用,那么,在for语句内声明它是一个很好的习惯。但是,在循环外就不能使用它了。因为,它的作用范围被限制于该for语句范围内!31又例如:求1+2+…+100。//SumWithFor.javapublicclassSumWithFor{
publicstaticvoidmain(String[]args){
intsum=0;
for(inti=1;i<=100;
i++)
sum+=i;
System.out.println("1+2+…+100="+
sum
);
}}truefalsei<100
sum+=ii=0i++sum=032在String类中,方法charAt(i)用于返回字符串中第i个字符;而方法length()则用于返回字符串的长度。下面是它们的使用示例: Stringline=input.nextLine(); intlengthOfline=line.length(); System.out.println("该行字符的长度为:"+lengthOfline); System.out.println("第"+0+"个字符是:"+line.charAt(0)); System.out.println("第"+1+"个字符是:"+line.charAt(1)); System.out.println("第"+5+"个字符是:"+line.charAt(5));
下面我们来编写一个用来统计从键盘输入的一行字符中英文字母和数字字符的个数。33importjava.util.Scanner;
publicclassCharactersCount{ publicstaticvoidmain(String[]args){ Scannerinput=newScanner(System.in); int
letterCounter
=
0,digitCounter
=
0; charch; System.out.print("请输入一行字符(回车结束):"); String
line
=
input.nextLine(); int
lengthOfline=
line.length(); for(int
i
=
0;
i
<lengthOfline;
i++)
{ ch
=
line.charAt(i); if(ch>='A'&&ch<='Z'||ch>='a'&&ch<='z')
letterCounter++; else
if(ch>='0'&&ch<='9')
digitCounter++; } System.out.println("该行字符的长度为:"+lengthOfline); System.out.println("其中,英文字母的个数为:"+
letterCounter); System.out.println("其中,数字字符的个数为:"+
digitCounter); }}34注意
for循环中的初始操作以及每次迭代后的操作,都可以是用0个或多个用逗号隔开的表达式。例如: for(i=0,j=0;(i+j<10);i++,j++){ ...... }例子:判断一个键盘输入的字符串是否回文. Stringword=input.nextLine(); intlengthOfword=word.length(); for(i
=
0,j=lengthOfword-1;i<j;i++,
j--)
if(word.charAt(
i
)!=word.charAt(
j
))
break; if(i
<
j) System.out.println("该字符串不是回文!"); else System.out.println("该字符串是回文。");35
publicstaticbooleanisPalindrome(Stringstr){//判断str是否为回文字符串
intlen=str.length();//返回字符串长度
for(intindex=0;index<len/2-1;index++){if(str.charAt(index)!=str.charAt(len-index-1)){//对称的两个字符比较
returnfalse;}}returntrue;}36注意如果省略
for循环中的循环条件,则被默认为是true。因此下面的语句是等价的: for(
;;){ ...... }等价与 for(
;true
;){ ...... }及 while(
true
){ ...... }374.5
采用哪种循环
while循环和for循环称为预测试循环,因为循环条件是在循环体执行前被测试的,而do-while循环则称为后测试循环,因为其循环条件是在循环体执行后测试的。
while循环总是可以转化为for循环。如下所示:
while(循环条件){ // ...... } for(;循环条件;){ //循环体 ...... }38
除某种特殊情况外,for循环通常也都能转化为while循环: for(初始操作;循环条件;每次迭代后的操作){ //循环体 ...... }
初始操作; while(
循环条件
){ //循环体 ......
每次迭代后的操作; }
建议使用自己觉得最自然、最舒服的一种循环语句。通常,如果已经提前知道重复次数,那就使用for循环(就像打印字符串100次)。如果无法确定重复次数,就使用while循环(就像读入一些数直到读入0为止)。如果在检验循环条件前需要执行循环体,那就使用do-while循环。39警告在for子句(或者while)和循环体之间多写分号是一个常见的错误。因为,这都将表示循环体是空语句块。如下所示:
for(....;....;.....); for(....;....;.....){}; { { ...... ..... } }或者 while(....); while(....){}; { { ...... ..... } }
使用行尾块风格是避免这种错误的最好办法: for(....;....;.....){ while(....){ ...... ..... } }40
但是,在do-while循环中,却需要用分号来结束循环: do{ ..... }while(.....);414.6
嵌套循环
在一个循环语句(while循环、for循环、do-while循环)内又包含另一个循环语句(while循环、for循环、do-while循环)称为循环语句嵌套。并且三种循环语句可以相互嵌套。程序清单4-5是使用嵌套for循环打印一个乘法表的程序。其运行示例如下图。42//源程序清单4-5MultiplicationTable.javaimportjava.util.Scanner;publicclassMultiplicationTable{publicstaticvoidmain(String[]args){ System.out.println("\n 乘法表\n"); System.out.print(""); for(inti=1;i<=9;i++) System.out.print(""+i); System.out.println("\n----------------------------------------"); for(inti=1;i<=9;i++){ System.out.print(i+"|"); for(intj=1;j<=9;j++) System.out.printf("%4d",i*j); System.out.println(); }}}提示循环嵌套中的内、外层循环控制变量(例如,i、j)不能同名。它们的意义以及它们之间的关系,好比手表的时针、分针和秒针:时针走一格,分针走一圈;分针走一格,秒针走一圈。43程序清单4-6是使用嵌套for循环打印右边图案的程序。//源程序清单4-6DigitalPattern.javaimportjava.util.Scanner;publicclassDigitalPattern{publicstaticvoidmain(String[]args){ for(inti=1;i<=6;i++){ for(intj=1;j<=i;j++) System.out.print(j+""); System.out.println(); }}}11212312341234512345612345612345123412312144程序清单4-6-1是使用嵌套while循环打印上述图案的程序。//源程序清单4-6-2DigitalPattern2.javaimportjava.util.Scanner;publicclassDigitalPattern2{publicstaticvoidmain(String[]args){ inti=1,j; while(i<=6){ j=1; while(j<=i){ System.out.print(j+""); j++; } System.out.println(); i++; }}}显然,对于计数型循环,for语句更胜于while语句。454.7
实例学习循环语句是程序设计的基础,编写循环语句的能力对于学习程序设计是非常必要的、也是非常重要的。如果能够使用循环编写程序,你就懂得如何编程了!正是由于这个原因,本节将提供三个实例,学习如何使用循环来解决问题。
值得再次提醒的是:在编写解决问题的程序之前,不要立即就开始写代码,应该首先考虑一下在不涉及怎样编写代码的情况下,如何手工解决它的逻辑方案。一旦有了一个逻辑方案,再将它翻译成Java语言的代码。(当然,翻译方式不是唯一的。例如,可以选择使用for语句,也可以选择while语句。)464.7.1
求最大公约数其算法可以描述如下:(i)输入两个整数n1、n2。(ii)(由于1可能不是它们的最大公约数,所以可以检测
2、3、4......
≤
n1及n2的整数)取
k=2;(iii)当k是
≤
n1及n2的整数时,重复执行下面两步操作:
i)k是n1、n2的最大公约数吗? 如果是的,则最大公约数gcd就是k;(即gcd=k)
ii)k加1;(iv)显示“最大公约数是”gcd。上面算法中的(ii)、(iii)可以翻译成下面的代码:提示一个问题常常有多种解决方案。最大公约数问题就有许多解决方案。一个更有效的解决方案是使用经典的“欧几里得”算法(见习题)。47
上面算法中的(ii)、(iii)可以翻译成下面的代码:intgcd=1;//假定最大公约数为1for(intk=2;k<=n1&&k<=n2;k++)if(n1%k==0&&n2%k==0)gcd=k;}intgcd=1;//假定最大公约数为1intk=2;while(k<=n1&&k<=n2){if(n1%k==0&&n2%k==0)gcd=k;k++;}48下面是这个算法的运行示例:49程序清单4-7是完整的程序。//源程序清单4-7GCD.javaimportjava.util.Scanner;importjavax.swing.JOptionPane;publicclassGCD{publicstaticvoidmain(String[]args){ Scannerinput=newScanner(System.in); System.out.print("请输入第一个数:"); intn1=input.nextInt(); System.out.print("请输入第二个数:"); intn2=input.nextInt(); intgcd=1; for(intk=2;k<=n1&&k<=n2;k++) if(n1%k==0&&n2%k==0) gcd=k;System.out.println("最大公约数是:"+gcd);}}算法说明:由于在本算法的循环中,
if语句的作用是从每一个可能的k中筛选出最新的最大公约数。因此,这类循环体的算法也被称为“筛选器”算法。504.7.2
预测未来学费
假设某大学今年的学费是10000美金,并以每年7%的速度增加。试问:多少年之后学费会翻倍?首先考虑如何手工解决它:第二年是第一年乘以1.07,.....未来的一年都是前一年乘以1.07。所以,每年的学费可以如下计算:doubletuition=10000;intyear=1;tuition=tuition*1.07;year++;tuition=tuition*1.07;year++;tuition=tuition*1.07;year++;......不断地计算下去,直到学费tuition达到或者超过20000美金为止。51现在可以将这个逻辑翻译成使用循环结构实现的下面这段代码: doubletuition=10000; intyear=1; while(tuition<=20000){ tuition=tuition*1.07; year++; }在本算法的循环体中,变量tuition的值也是由自身的旧值迭代而得的。而year则是一个计数器。52程序清单4-8是完整的程序。//源程序清单4-8FutureTuition.javapublicclassFutureTuition{publicstaticvoidmain(String[]args){ doubletuition=10000; intyear=1; while(tuition<=20000){ tuition=tuition*1.07; year++; } System.out.println(year+"后,学费将翻倍!");}}534.7.3
枚举法
在某些问题中,需要对可能出现的大量情况进行一一测试,以判断是否满足某些(或某个)求解的条件。采用循环语句可以方便地来解决。例如,“百元买百鸡”问题。假定小鸡每只0.5元,公鸡每只2元,母鸡每只3元。现在有100元钱,要求买100只鸡。编程列出所有可能的买鸡方案。设,小鸡、公鸡和母鸡分别为chickens、cocks、hens只。根据题意,列出方程组如下: chickens+cocks+hens=100 0.5*chickens+2*cocks+3*hens=10054
枚举法的基本思想,就是在所有可能的chickens、cocks、hens值中,找出满足方案的解。按照这个思想,chickens、cocks、hens可能的取值如下:
chickens:0~100、 cocks:0~100、 hens:0~100.
那么,接下来的问题就是:在上面这三个取值范围中,哪些值是满足解决方案的?55程序清单4-9是《算法一:三重嵌套》完整的程序。//源程序清单4-9HundredYuanToBuyHundredChickens1.javaimportjava.util.Scanner;publicclassHundredYuanToBuyHundredChickens1{publicstaticvoidmain(String[]args){ intchickens,cocks,hens; System.out.println("chickens\tcocks\thens"); for(chickens=0;chickens<100;chickens++) for(cocks=0;cocks<100;cocks++) for(hens=0;hens<100;hens++) if((chickens+cocks+hens==100) &&(0.5*chickens+2*cocks+3*hens==100)) System.out.println(chickens +"\t"+cocks+"\t"+hens);}}56程序清单4-10是《算法二:优化为两重嵌套》完整的程序。//源程序清单4-10//HundredYuanToBuyHundredChickens2.javaimportjava.util.Scanner;publicclassHundredYuanToBuyHundredChickens2{publicstaticvoidmain(String[]args){ intchickens,cocks,hens; System.out.println("chickens\tcocks\thens"); for(hens=0;hens<33;hens++) for(cocks=0;cocks<50;cocks++){ chickens=100-hens-cocks; if(0.5*chickens+2*cocks+3*hens==100) System.out.println(chickens+","+cocks+"," +hens); }}}57*4.7.4
蒙特卡洛模拟
为了更多地学习编程解决问题,本节给出使用蒙特卡洛方法来估算π的值。为了更好地理解这个方法,需要画出一个圆的外接正方形。如下图所示:1-1-11
假设这个圆的半径是1,那么圆面积就是π而外接正方形的面积就是4。随机产生正方形中的一个点,该点落在这个圆内的概率是
圆面积/正方形面积:π/4。编写程序,在正方形内随机产生1000000个点,用变量numberOfHits对落在圆内的点进行计数。由于numberOfHits≈1000000*(π/4),所以,就可以利用式子 π=4*numberOfHits/1000000来估算π的近似值了。完整程序如程序清单4-9所示。(x,y)且有:x2+y2≤158程序清单4-11是蒙特卡洛模拟的完整程序。//源程序清单4-11MonteCaloSimulation.javaimportjava.util.Scanner;importjavax.swing.JOptionPane;publicclassMonteCaloSimulation{publicstaticvoidmain(String[]args){ finallongNUMBER_OF_TRIALS=10000000; intnumberOfHits=0; for(inti=0;i<NUMBER_OF_TRIALS;i++) { doublex=Math.random()*2.0-1; doubley=Math.random()*2.0-1; if(x*x+y*y<=1) numberOfHits++; } doublepi=4.0*numberOfHits/NUMBER_OF_TRIALS; System.out.println("π的值是:"+pi);}}说明
本算法也属于“筛选器”算法。59注:蒙特卡洛模拟方法的原理是当问题或对象根据抽样计算统计量或者参数的值,随着模拟次数的增多,可以通过对各次统计量或参数的估计值求平均的方法得到稳定结论。(想要了解更多的有关知识,请自行上网检索。)604.8
关键字break和continue
我们已在switch语句中使用过break语句,你也可以在一个循环中使用break来终止循环。下面的代码是将1到20的整数加到sum中,直到sum的值大于或等于100为止。 intsum=0; intnumber=0; while(number<20){ number++; sum+=number; if(sum>=100) break; }
//结束循环61程序清单4-12中给出了完整的程序。//源程序清单4-12TestBreak.javaimportjava.util.Scanner;importjavax.swing.JOptionPane;publicclassTestBreak{publicstaticvoidmain(String[]args){ intsum=0; intnumber=0; while(number<20){ number++; sum+=number; if(sum>=100) break; } System.out.println("number的值是:"+number); System.out.println("sum的值是:"+sum);}}number的值是:14sum的值是:105如果没有if语句,程序就会计算1到20的和。其运行结果是:number的值是:20sum的值是:21062
你也可以在循环中使用关键字continue。当程序遇到continue时,它会结束当前迭代,程序控制将转向循环体的末尾。换句话说,continue只是跳出了一次迭代,而break则是跳出整个循环。下面的代码是将1到20中除去10和11外的整数都加到sum中。 intsum=0; intnumber=0; while(number<20){ number++; if(number==10||number==11) continue; sum+=number; }63程序清单4-13中给出了完整的程序。//源程序清单4-13TestContinue.javaimportjava.util.Scanner;importjavax.swing.JOptionPane;publicclassTestContinue{publicstaticvoidmain(String[]args){ intsum=0; intnumber=0; while(number<20){ number++; if(number==10||number==11) continue; sum+=number; } System.out.println("sum的值是:"+sum);}}sum的值是:189如果没有if语句,程序就会计算1到20的和。其运行结果是:sum的值是:21064注意虽说break和continue可以为循环提供额外的控制,并在某种情况下还可以简化程序设计。但是,过度地使用或者不正确地使用会使得程序难以读懂并难以测试。通常,总是可以编写出在循环中不使用它们的程序。也就是说,只有在能够简化程序代码并使程序更容易阅读的情况下,才可以适当地使用它们。
下面使用break来改写程序清单4-1猜数字的程序。程序请参见程序清单4-11。65//源程序清单4-11GuessNumberUsingBreak.javaimportjava.util.Scanner;publicclassGuessNumberUsingBreak{publicstaticvoidmain(String[]args){ intnumber=(int)(Math.random()*101); Scannerinput=newScanner(System.in); System.out.println("请你猜一个0~100的魔数"); intguess=-1; while(true){//重复执行下面的循环体 System.out.print("请你输入一个猜测数:"); guess=input.nextInt(); //读入用户输入的猜测数 if(guess==number){ System.out.println("恭喜你猜对了!");
} elseif(guess>number) System.out.println("你猜大了!"); else System.out.println("你猜测了!"); }//循环结束}}
break;//跳出循环66注意:在while和do-while语句中,continue之后会马上去计算并测试循环条件;而在for语句中,continue之后则先执行每次迭代后的操作,然后做计算并测试循环条件。如下所示:inti=1;while(i<20){sum+=i;if(i%2==0) continue;i++;}inti=1;do{sum+=i;if(i%2==0) continue;i++;}while(i<20);for(i=1;i<20;i++){sum+=i;if(i%2==0) continue;}67问题:显示前50个素数(每行10个)
大于1的整数,如果它的正因子只有1和它自己,那么,该整数就是素数。例如,2、3、5、7都是素数,而4、6、8、9不是。在该问题中,需要解决的主要问题有:•如何判断一个给定数是否素数?•如何统计素数的个数?•如何打印每个素数并且每行打印10个?68该问题的初步算法可以用Java伪代码来描述如下:count=0; //素数的计数器变量count初始化number=2;//第一个可能的素数从2开始(1不是质数)while(count<50){//素数个数不能超过50个 if(number是素数){ count++;
显示number;//每行显示10 } number++;}//如何判断number是否素数?69
为了判断
number是否素数,需要检测它是否能被2、3、4、...number/2的整数整除。如果能被整除,那它就不是素数。这个算法可以描述如下:booleanisPrime=true;//先假定number是素数for(intdiv=2;div<=number/2;div++)
if(number%div==0){
isPrime=false; break;
}显然,当上面这个循环结束后,isPrime若为true,则number是素数。因此,接下去就是那个if语句来处理是否显示number了:if(isPrime){count++;
显示number;
}70//源程序清单4-12PrimeNumber.javapublicclassPrimeNumber{publicstaticvoidmain(String[]args){ intcount=0;//素数计数器count初始化 intnumber=2; //第一个给定数number为2. System.out.println("前50个素数是:\n"); while(count<50){ booleanisPrime=true;//假设number是素数 for(intdiv=2;div<=number/2;div++)
if(number%div==0){
isPrime=false;//number不是素数
break;//终止本for循环语句循环
}//for循环结束
if(isPrime){
count++; if(count%10==0)//显示number后换行 System.out.println(number); else//显示number后不换行 System.out.print(number+""); } number++;
}//while循环结束}
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论