一. 程序逻辑控制
1. 顺序结构
顺序结构,指按照代码的书写顺序一行一行的执行
2. 分支结构
2.1 if语句
1. 格式一
if(布尔表达式){
// 语句
}
2. 格式二
if(布尔表达式){
// 语句1
}else{
// 语句2
}
3. 格式三
if(布尔表达式1){
// 语句1
}else if(布尔表达式2){
// 语句2
}else{
// 语句3
}
代码实现
判断是奇数还是偶数
`int num = 10;`
`if (num % 2 == 0) {`
`System.out.println("num 是偶数");`
`} else {`
`System.out.println("num 是奇数");`
`}`
【注】
- 无论哪种格式,一次只会执行一个语句,不会既执行if,又执行else if
- else只和最近的if匹配,不分是否对齐
- 编译时if和else可以不加大括号,但不推荐,实际开发中我们最好加上大括号
2.2 switch
switch的使用局限很大,并不像if那样方便
1. 格式
switch(表达式){
case 常量值1:{
语句1;
[break;]
}
case 常量值2:{
语句2;
[break;]
}
default:{
内容都不满足时执行语句;[break;]
}
}
2. 执行流程
- 先计算表达式的值
- 值和case一一比较,若有case符合,则执行,若都没有,则执行default
【注】
- case的值不能重复
- switch括号内只能是≤四个字节的基本数据类型"byte、char、short、int",和引用数据类型"String常量串,枚举类型"
- break不要遗漏,不然代码会一直往下滑,滑到有break的语句再停止
- 不建议switch嵌套使用
- switch不能像if那样表达复杂条件
3. 循环结构
3.1 while循环
1. 格式
while(循环条件){
循环语句;
}
2. 代码练习
打印1到10的数字(错误代码)
`int num = 1;`
`while (num <= 10); {`
`System.out.println(num);`
`num++;`
`}`
【注】
- while括号后不要加分号,上边的代码进入死循环就是因为加了分号。while没有循环语句,导致num<=10恒成立,进入死循环
3.2 for循环
1. 格式
for(表达式1;布尔表达式2;表达式3){
表达式4;
}
2. 代码练习
打印1到10的数字
`for (int i = 1; i <= 10; i++) {`
`System.out.println(i);`
`}`
【注】for括号后不要加分号
3.3 do while循环(很少用)
不管三七二十一先执行一次语句,再开始循环
1. 格式
do{
循环语句;
}while(循环条件);
2. 代码练习
打印1到10的数字
`int num = 1;`
`do {`
`System.out.println(num);`
`num++;`
`} while (num <= 10);`
【注】该循环需要加分号
3.4 break和continue
- break是提前结束循环
- continue只跳过本次循环
4. OJ题的输入输出
4.1 输出
System.out.println(msg); // 输出一个字符串, 带换行
System.out.print(msg); // 输出一个字符串, 不带换行
System.out.printf(format, msg); // 同c语言的格式化输出
4.2 输入
OJ题中会需要进行输入操作:使用 Scanner 读取字符串/整数/浮点数;循环输入多个数据
1. 使用 Scanner 读取字符串/整数/浮点数
Scanner 变量名 = new Scanner(System.in);
import java.util.Scanner; // 需要导入 util 包
Scanner sc = new Scanner(System.in);
//输入字符串 -- nextLine()
String name = sc.nextLine();
//输入整数 -- nextInt()
int age = sc.nextInt();
//输入浮点数 -- nextFloat()
float salary = sc.nextFloat();
2. 使用 Scanner 循环读取 N 个数字
Scanner sc = new Scanner(System.in);
while (sc.hasNextInt()) {
int tmp = sc.nextInt();
}
【注】当循环输入多个数据的时候,想取消输入时,Windows 上使用 ctrl + z, Linux / Mac 上使用 ctrl + d。在后续oj题当中,遇到IO类型的算法题,有各种循环输入的要求
5. 程序逻辑控制实现(猜数字游戏)
二. 方法
1. 方法概念
- 方法相当于c语言中的函数,必须定义在类内,比如main方法也是定义在类内的
- 方法没有方法声明之说
- 方法不能嵌套定义,但可以嵌套使用
2. 方法格式
修饰符 返回值类型 方法名称(参数类型){
方法体代码;
}
由于知识量不足,修饰符先固定为public static,格式如下
public static 返回值类型 方法名(参数列表){
//方法体
}
3. 方法的调用(重点)
3.1 方法的实参和形参
实参是main方法中的变量,方法调用时,会将实参的值拷贝一份传给形参
3.2 传值调用(传基础类型)
传值调用:对形参的操作不影响实参
【代码演示】
`public class TestMethod {`
`public static void main(String[] args) {`
`int a = 10;`
`int b = 20;`
`swap(a, b);`
`System.out.println("main: a = " + a + " b = " + b);`
`}`
`public static void swap(int x, int y) {`
`int tmp = x;`
`x = y;`
`y = tmp;`
`System.out.println("swap: x = " + x + " y = " + y);`
`}`
`}`
`// 运行结果`
`swap: x = 20 y = 10`
`main: a = 10 b = 20`
3.3 传"址"调用(传引用类型)
传址调用:对形参的操作影响实参
【代码演示】
`public class TestMethod {`
`public static void main(String[] args) {`
`int[] arr = {10, 20};`
`swap(arr);`
`System.out.println("arr[0] = " + arr[0] + " arr[1] = " + arr[1]);`
`}`
`public static void swap(int[] arr) {`
`int tmp = arr[0];`
`arr[0] = arr[1];`
`arr[1] = tmp;`
`}`
`}`
`// 运行结果`
`arr[0] = 20`
`arr[1] = 10`
4. 方法的重载
4.1 为什么要重载
比如写了一个求两个整数之和的方法,当再想求两个小数之和的方法就需要重新写一份代码,方法名也要再取,为了不用取方法名,就有了重载,也就是生活中说的一词多义
4.2 重载概念
【概念】如果多个方法的名字相同,参数列表不同,那么方法之间构成重载
【重载条件】
- 方法名相同
- 参数列表不同(参数的类型/数量/次序不同)
4.3 方法签名
【提问】
- 多个方法名相同的情况下,编译器是如何知道我调用的哪个方法?
- 方法中不能定义两个同名的局部变量,为什么类中的方法却可以?
【定义】经过编译器编译修改过之后方法最终的名字。具体方式:方法全路径名+参数列表+返回值类型,构成方法完整的名字。
【代码演示】
`public class TestMethod {`
`public static int add(int x, int y){`
`return x + y;`
`}`
`public static double add(double x, double y){`
`return x + y;`
`}`
`public static void main(String[] args) {`
`add(1,2);`
`add(1.5, 2.5);`
`}`
`}`
在编译器看来,int add(int x, int y)是(II)I,表示参数类型是int,返回值也是int;double add(double x, double y)是(DD)D,表示参数类型是double,返回值也是double
5. 方法的应用(递归)
5.1 递归的概念
【定义】将原问题拆成几个子问题,子问题的解决思路与原问题有相同的解法,解决一个个子问题后就解决了原问题。严格讲,一个方法在执行过程中调用自身,就称为"递归"
【递归的条件】
- 有一个起始条件(递归的出口)
- 有一个递推公式(将原问题划分成子问题,子问题的解决思路必须与原问题相同)
5.2 递归的练习
1. 按顺序打印一个数字的每一位(例如 1234 打印出 1 2 3 4)
【代码逻辑】
- 先找子问题:只打印每个数字的最后一位。打印123,先打印3,123%10,123/10;打印2,12%10,12/10;打印1,1是起始条件。子问题解决思路和原问题解决思路相同,递推公式为n/10
- 找起始条件:只打印个位时
【代码实现】
public static void print(int num) {
if (num/10 != 0) {
print(num / 10);
}
System.out.println(num % 10);
}
2. 递归求 1 + 2 + 3 + … + 10
【代码逻辑】
- 找子问题:只求n和n的前一个数字。求1 + 2 ,2+(2-1);求1 + 2 + 3 ,3+(3-1)+((3-1)-1),子问题与原问题解决思路相同,递推公式为,n+(n-1)
- 找起始条件:n = 1时
【代码实现】
public static int sum(int num) {
if (num == 1) {
return 1;
}
return num + sum(num - 1);
}
3. 写一个递归方法,输入一个非负整数,返回组成它的数字之和. 例如,输入 1729, 则应该返回 1+7+2+9,它的和是19
【代码逻辑】
- 找子问题:只取最后一位。递推公式为,n/10
- 找起始条件:n/10 = 0
【代码实现】
public static int sum(int num) {
if (num/10 == 0) {
return num;
}
return num % 10 + sum(num / 10);
}
4. 求斐波那契数列的第 N 项(1 1 2 3 5 8…)
【代码逻辑】
- 找子问题:从第三项开始,n=(n-1)+(n-2)。如,求第四个的值=求第三项+第二项=(求第一项+第二项)+(return 1)=3
- 找起始条件:n = 1或2
【代码实现】
public static int fib(int n) {
if (n == 1 || n == 2) {
return 1;
}
return fib(n - 1) + fib(n - 2);
}