目录
流程控制语句是用来控制程序中各语句执行顺序的语句,可以把语句组合成能完成一定功能的小逻辑模块。
控制语句分为三类:顺序结构,选择结构,循环结构。
顺序结构
代表 “先执行a,再执行b” 的逻辑。【从上到下,从左到右,逐行执行】
选择结构 (分支结构)
代表 “如果···,则···” 的逻辑。【根据条件判断,执行某一块代码】
一,if 语句
1,单分支结构
if (布尔表达式) {
语句块;
}
- if 语句对布尔表达式进行一次判断,若判断为真,则执行 { } 中的代码,否则跳过该语句块。
2,双分支结构
if (布尔表达式){
语句块1;
} else {
语句块2;
}
- 当布尔表达式为真时,执行语句块1,否则,执行语句块2。
-
代替写法:三元运算符———条件 ? 值1 : 值2;
先判断条件,如果条件是true,返回值1,否则,返回值2。
3,多分支结构
if (布尔表达式){
语句块1;
} else if (布尔表达式2){
语句块2;
}……
else if (布尔表达式 n){
语句块n;
} else {
语句块n+1;
}
- 当布尔表达式1为真时,执行语句块1;否则,判断布尔表达式2,当布尔表达式2为真时,执行语句块2;否则,继续判断布尔表达式3······;如果1~n个布尔表达式均判定为假时,则执行语句块n+1,也就是else部分。
- 好处:只要满足一个 分支以后,后面的分支就不需要判断了 --》效率高
- 分别叙述单选择、双选择、多选择的区别
单选择、双选择和多选择结构的主要区别在于它们能够处理的条件数量和逻辑。
单选择结构:单选择结构通常使用if 语句实现,用于判断一个条件是否满足,如果满
足则执行特定的代码块,否则不执行任何操作。例如,if(条件){语句;}。这种结构
适用于只有两个选择的情况,即满足条件执行某操作,不满足则不执行。
· 双选择结构:双选择结构使用 if-else 语句实现,用于判断两个条件中哪一个满足。如
果第一个条件满足,则执行第一个代码块;如果不满足,则判断第二个条件是否满足,满足
则执行第二个代码块。这种结构适用于在两个选项中选择一个执行的情况23。
· 多选择结构:多选择结构可以使用 if-else if-else 语句或 switch 语句实现,用于
判断多个条件中哪一个满足。如果第一个条件满足,则执行第一个代码块;如果不满足,则
判断第二个条件是否满足,以此类推。这种结构适用于有多个选项需要判断的情况1 3。
4,随机数
- 依靠java中的一个类:Math
- random : 返回带正号的 double 值,该值大于等于0.0且小于1.0。【生成随机数】
- 应用:Math.random() ------------> [0.0,1.0)
Math.random()*6 ------------> [0.0,6.0)
(int)( Math.random()*6 )------------> [0,5]
(int)( Math.random()*6 ) +1 ------------> [0,6]
二,switch语句
-
多分支结构(多值情况)
switch(表达式){
case 值1:
语句序列1;
break;
case 值2:
语句序列2;
break;
··· ··· ··· ··· ···
default:默认语句;
}
-
switch语句会根据表达式的值从相匹配的case标签处开始执行,一直执行到break语句处或者是switch语句的末尾。如果表达式的值与任一case值不匹配,则进入default语句(如果存在default语句的情况)。
-
switch后面是一个(),()中表达式返回的结果是一个等值,这个等值的类型可以为:
int,byte,short,char,String,枚举类型
-
为了防止代码的“穿透”效果:在每个分支后面加上一个关键词break,遇到break这个分支就结束了
-
default分支可以写在任意的位置上,但是如果没有在最后一行,后面必须加上break关键字,
- 如果在最后一行的话,break可以省略。
-
当布尔表达式是等值判断的情况,可以使用 if-else 多分支结构或者 switch 结构,
如果布尔表达式区间判断的情况,则只能使用 if-else 多分支结构。
- if多分支语句和switch多分支语句的异同之处
相同之处:都是分支语句,对超过一种的情况进行判断处理。
不同之处:
- switch更适合用于多分支情况,就是有很多种情况需要判断处理,判断条件类型单一,只有一个入口,在分支执行完后(如果没有break跳出),不加判断地执行下去;
- if—elseif---else多分枝主要适用于分支较少的分支结构,判断类型不是单一,只要一个分支被执行后,后边的分支不再执行。
- switch为等值判断(不允许比如>= <=),而if为等值和区间都可以,if的使用范围大。
- switch语句的功能是否完全可以使用if -else if -else多选择结构来代替?如果是,为什么还需要switch结构?
switch语句的功能可以用if-else if-else多选择结构来代替。这是因为switch语句和if-else if-
else结构都可以实现条件分支的选择,虽然switch语句在某些情况下更为简洁和清晰,但从
功能上来说,if-else if-else结构足以覆盖switch语句的所有功能。
然而,尽管可以用if-else if-else结构来代替switch语句,但在实际使用中,switch语句有其
独特的优势和适用场景。首先,switch语句在处理固定特定值的等值判断时更为简洁和清
晰,而if-else结构在处理范围判断时更为灵活。其次,switch语句的执行效率在某些情况下高于if-else结构,特别是当分支较多时,switch语句可以直接跳转到相关的case选项,而if-else结构需要对每个条件进行多次判断。
因此,虽然技术上可以用if-else结构代替switch语句,但在实际编程中,根据具体需求选择
使用switch语句还是if-else结构,可以使代码更加高效和易于理解。
循环结构
代表 “如果···,则再继续···” 的逻辑。【根据条件判断,重复执行某一块代码】
循环结构的组成: 循环条件(开始,终止,修改)+修改内容
- 什么情况下,会出现死循环?并写出一个例子来。
死循环通常发生在循环条件始终成立,或者循环体内没有改变循环结束条件的情况下。while(true){ // do something}
一,while循环
循环次数不固定。
while(布尔表达式){
循环体;
}
-
循环的作用:
将部分代码重复执行。 循环只是提高了程序员编写代码的效率,但是底层执行的时候依然是重复执行。
-
循环四要素:
(1)条件初始化 (2)条件判断
(3)循环体 (4)迭代
public static void main(String[] args) {
//求 1+2+3+4+5 的和
//1,定义变量
int num=1; //(1)条件初始化
//2,定义一个求和变量,用来接收和
int sum=0;
while(num<5){ //(2)条件判断
sum+=num; //(3)循环体
num++; //(4)迭代
}
System.out.println(sum);
}
-
在循环刚开始时,会计算一次“布尔表达式”的值,若条件为真,执行循环体。而对于后来每一次额外的循环,都会在开始前重新计算一次。
-
语句中应有使循环趋向于结束的语句,否则会出现无限循环–––"死"循环。
2,while和do-while循环的区别
while先判断后执行,第一次判断为false,循环体一次都不执行
do while先执行 后判断,最少执行1次。
如果while循环第一次判断为true, 则两种循环没有区别。
二,do-while循环【禁用】
do {
循环体;
} while(布尔表达式) ;
1,do-while循环结构会先执行循环体,然后再判断布尔表达式的值,若条件为真,执行循环体,当条件为假时结束循环。do-while循环的循环体至少执行一次。
三,for循环
循环次数固定。
for (初始表达式;布尔表达式;迭代因子){
循环体;
}
-
初始化部分 ----- 设置循环变量的初值
条件判断部分 ----- 为任意布尔表达式
迭代因子 ----- 控制循环变量的增减
-
for循环在执行条件判定后,先执行的循环体部分,再执行迭代因子。
- for循环相比while循环有什么优势?
主要优势在于其结构简洁明了,特别适用于循环次数已知的情况。 for循环的语法结构通常更简洁明了,包括初始化语句、条件检查和更新语句,所有这些都包含在一个结构中,使得代码更易读、更易维护
四,foreach
不考虑循环次数。
在使用 foreach 循环迭代数组元素时,并不能改变数组元素的值,因此不要对 foreach 的循环变量进行赋值。
for(数据类型 变量名:数组) {
需要执行的语句块;
}
五,关键字
1,break
----- 终止循环 (停住最近的循环),执行后面的代码。
public static void main(String[] args){
//功能:求1-100的和,当和第一次超过300的时候,停止程序
int sum = 0;
for(int i=1;i<=100;i++){
sum += i;
if(sum>300){//当和第一次超过300的时候
//停止循环
break;//停止循环
}
System.out.println(sum);
}
}
public static void main(String[] args){
outer: //----》定义标签结束的位置
for(int i=1;i<=100;i++){
System.out.println(i);
while(i==36){
break outer; // ----》根据标签来结束循环
}
}
}
2,continue
----- 停止()本次循环,进行下一次循环。
public static void main(String[] args){
//功能:输出1-100中被6整除的数:
//方式1:
/*
for(int i=1;i<=100;i++){
if(i%6==0){//被6整除
System.out.println(i);
}
} */
//方式2:
for(int i=1;i<=100;i++){
if(i%6!=0){//不被6整除
continue;//停止本次循环,继续下一次循环
}
System.out.println(i);
}
}
public static void main(String[] args){
outer: //---》定义标签结束的位置
for(int i=1;i<=100;i++){
while(i==36){
continue outer; //1-100没有36 根据标签结束循环
}
System.out.println(i);
}
}
3,return
-----终止当前方法,执行后面的方法
public static void main(String[] args){
//return:遇到return结束当前正在执行的方法
for(int i=1;i<=100;i++){
while(i==36){
return;
}
System.out.println(i);
}
System.out.println("-----");
}
4,System . exit (1)
-----终止当前程序
3,break和continue的作用
break: 结束当前循环并退出当前循环体。
break还可以退出switch语句
continue: 循环体中后续的语句不执行,但是循环没有结束,继续进行循环条件的判断(for循环还会i++)。continue只是结束本次循环。
- 在多重循环中,如何在内层循环中使用break跳出外层循环。
在多重循环中,可以使用带有标签的break语句跳出外层循环。 在内层循环中使用break语句时,加上外层循环的标签即可实现跳出外层循环的功能。
具体步骤如下:
在需要跳出的外层循环之前,给外层循环添加一个标签,例如 outer_loop:。
在内层循环中使用 break outer_loop; 语句,即可跳出外层循环。
注意事项:
使用带有标签的break语句虽然可以跳出多层循环,但容易导致代码结构混乱,建议尽量避免嵌套过多的循环。
六,二重循环
可以解决二元一次方程组问题
1,乘法口诀
public static void main5(String[] args) {
/*打印九九乘法表*/
/* System.out.println("。\t。\t。\t。\t。\t。\t。\t。\t。");
System.out.println("。\t。\t。\t。\t。\t。\t。\t。\t。");
System.out.println("。\t。\t。\t。\t。\t。\t。\t。\t。");
System.out.println("。\t。\t。\t。\t。\t。\t。\t。\t。");
System.out.println("。\t。\t。\t。\t。\t。\t。\t。\t。");
System.out.println("。\t。\t。\t。\t。\t。\t。\t。\t。");
System.out.println("。\t。\t。\t。\t。\t。\t。\t。\t。");
System.out.println("。\t。\t。\t。\t。\t。\t。\t。\t。");
System.out.println("。\t。\t。\t。\t。\t。\t。\t。\t。");*/
for (int i = 0; i <= 9; i++) {//i控制行数
/* System.out.println("。\t。\t。\t。\t。\t。\t。\t。\t。");*/
for (int j = 1; j <= i; j++) {//j控制每行中的个数
System.out.print(i + "*" + j + "=" + (i * j) + "\t");
}
System.out.println();
}
}
【1】长方形
for(int j=1;j<=4;j++){//j:控制行数 //********* for(int i=1;i<=9;i++){//i:控制*的个数 System.out.print("*"); } //换行: System.out.println(); }
【2】距离前面有一定空隙的长方形:
for (int j = 1; j <= 4; j++) {//j:控制行数 //加入空格: for (int i = 1; i <= 5; i++) {//i:控制空格的个数 System.out.print(" "); } //********* for (int i = 1; i <= 9; i++) {//i:控制*的个数 System.out.print("*"); } //换行: System.out.println(); }
【3】平行四边形
for (int j = 1; j <= 4; j++) {//j:控制行数 //加入空格: for (int i = 1; i <= (9 - j); i++) {//i:控制空格的个数 System.out.print(" "); } //********* for (int i = 1; i <= 9; i++) {//i:控制*的个数 System.out.print("*"); } //换行: System.out.println(); }
【4】三角形
for (int j = 1; j <= 4; j++) {//j:控制行数 //加入空格: for (int i = 1; i <= (9 - j); i++) {//i:控制空格的个数 System.out.print(" "); } //********* for (int i = 1; i <= (2 * j - 1); i++) {//i:控制*的个数 System.out.print("*"); } //换行: System.out.println(); }
【5】菱形
//上面三角形: for (int j = 1; j <= 4; j++) {//j:控制行数 //加入空格: for (int i = 1; i <= (9 - j); i++) {//i:控制空格的个数 System.out.print(" "); } //********* for (int i = 1; i <= (2 * j - 1); i++) {//i:控制*的个数 System.out.print("*"); } //换行: System.out.println(); } //下面三角形: for (int j = 1; j <= 3; j++) {//j:控制行数 //加入空格: for (int i = 1; i <= (j + 5); i++) {//i:控制空格的个数 System.out.print(" "); } //********* for (int i = 1; i <= (7 - 2 * j); i++) {//i:控制*的个数 System.out.print("*"); } //换行: System.out.println(); }
【6】空心菱形
//上面三角形: for (int j = 1; j <= 4; j++) {//j:控制行数 //加入空格: for (int i = 1; i <= (9 - j); i++) {//i:控制空格的个数 System.out.print(" "); } //********* for (int i = 1; i <= (2 * j - 1); i++) {//i:控制*的个数 if (i == 1 || i == (2 * j - 1)) { System.out.print("*"); } else { System.out.print(" "); } } //换行: System.out.println(); } //下面三角形: for (int j = 1; j <= 3; j++) {//j:控制行数 //加入空格: for (int i = 1; i <= (j + 5); i++) {//i:控制空格的个数 System.out.print(" "); } //********* for (int i = 1; i <= (7 - 2 * j); i++) {//i:控制*的个数 if (i == 1 || i == (7 - 2 * j)) { System.out.print("*"); } else { System.out.print(" "); } } //换行: System.out.println(); }
七,三重循环
解决三元一次方程组问题
例题:
百钱买百鸡:
公鸡5文钱一只,母鸡3文钱一只,小鸡3只一文钱,
用100文钱买一百只鸡,其中公鸡,母鸡,小鸡都必须要有,问公鸡,母鸡,小鸡要买多少只刚好凑足100文钱。
数学:
设未知数:
公鸡:x只
母鸡:y只
小鸡:z只
x+y+z=100只
5x+3y+z/3=100钱
import java.util.*;
public class PanTi {
public static void main(String[] args) {
// 麻烦方式:
for (int x = 1; x <= 100; x++) {
for (int y = 1; y <= 100; y++) {
for (int z = 1; z <= 100; z++) {
if ((x + y + z == 100) && (5 * x + 3 * y + z / 3 == 100) && (z % 3 == 0)) {
System.out.println("麻烦版" + x + "\t" + y + "\t" + z);
}
}
}
}
// //优化:
for (int x = 1; x <= 19; x++) {
for (int y = 1; y <= 31; y++) {
int z = 100 - x - y;
if ((5 * x + 3 * y + z / 3 == 100) && (z % 3 == 0)) {
System.out.println("优化版" + x + "\t" + y + "\t" + z);
}
}
}
}
}
递归
一,什么是递归
递归算法是一种直接或者间接地调用自身算法的过程。在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解
然而,使用递归时必须小心,因为如果没有正确的终止条件,递归可能会进入无限循环,从而导致StackOverflowError(无限循环)
二,使用递归
计算n!
public class Test {
public int factorial(int n) {
if (n == 1 || n == 0){
return n;//终止条件
}else{
return n * factorial(n - 1);//递归调用
}
}
public static void main(String[] args) {
Test test = new Test();
System.out.println(test.factorial(6));
}
}
例题: 使用递归法计算 n ! {加了输入和一个现实的格式限制}
/** * 请使用递归算法算法计算n! * * @param args */ /** * 主程序入口 * 该方法首先提示用户输入一个数字,然后计算该数字的阶乘 * 同时,它还会生成一个字符串,表示阶乘计算的过程 * 最后,它将计算结果和过程字符串一起打印到控制台 */ public static void main(String[] args) { System.out.println("请输入数字:"); Scanner input = new Scanner(System.in); int n = input.nextInt(); long sum = method(n); String str = method2(n); System.out.println(n + "!" + "=" + str + "=" + sum); } /** * 生成阶乘计算的过程字符串 * 该方法接收一个整数n,返回一个字符串,表示从1到n的乘法过程 * 例如,当n为5时,返回的字符串为"1*2*3*4*5" * * @param n 阶乘计算的数字 * @return 表示阶乘计算过程的字符串 */ public static String method2(int n) { String result = ""; for (int i = 1; i <= n; i++) { result += (i + "*"); } return result.substring(0, result.length() - 1); } /** * 计算给定数字的阶乘 * 使用递归方式计算n的阶乘,如果n等于1,则返回1,否则返回n乘以n-1的阶乘 * 注意:此方法假设输入的n是一个非负整数,否则可能会导致无限递归 * * @param n 阶乘计算的数字 * @return n的阶乘结果 */ public static int method(int n) { if (n == 1) { return 1; } else { return n * method(n - 1); } }
三,递归的优缺点
1,递归的优点:
(1)简洁性:
递归可以用较少的代码实现复杂的功能,相对于使用循环来处理嵌套结构,递归代码通常更简洁、易于理解和维护。
(2)可读性:
递归可以使代码更加可读和自解释,特别是对于涉及嵌套结构的问题,递归代码可以更直观地表示问题的解决方案。
(3)灵活性:
递归可以应对未知深度的数据结构,因为它不需要提前知道要处理的嵌套层级.
(4)问题分解:
递归通过将问题划分为更小的子问题,使得复杂问题的解决变得更加可行.
2,递归的缺点:
(1)性能开销:
递归可能会导致性能问题,尤其是当递归层级很深时。每次递归调用都需要在内存中创建一个新的函数上下文,这可能会占用大量的内存和处理时间.
(2)栈溢出:
如果递归层级过深,函数调用的堆栈可能会超出系统的限制,导致栈溢出错误。这通常可以通过限制递归层级或使用尾递归优化来避免。
(3)难以调试:
由于递归涉及到函数的自我调用,调试递归函数可能会变得复杂和困难。错误的递归调用可能导致死循环或无限递归,从而使得调试变得更加困难3。
4,递归的定义和优缺点
递归算法是一种直接或者间接地调用自身算法的过程。在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解。
递归算法解决问题的特点:
(1) 递归就是在过程或函数里调用自身。
(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
(3) 递归算法解题通常显得很简洁,但运行效率较低。所以一般不提倡用递归算法设计程序。
(4) 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。所以一般不提倡用递归算法设计程序。