数组 与 循环Arrays and Loops
数组Arrays
什么是
一堆同类型变量
案例对比
使用前
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int number = Console.readInt(); int digit1, digit2, digit3; digit1 = number % 10;number = number / 10; digit2 = number % 10;number = number / 10; digit3 = number % 10;number = number / 10; Console.println(digit3);Console.println(digit2);Console.println(digit1);
使用后
1 2 3*4 5*6 7 8*9 10 11*12 13 14*15*16*int number = Console.readInt(); int[] digits = new int[3]; digits[0] = number % 10;number = number / 10; digits[1] = number % 10;number = number / 10; digits[2] = number % 10;number = number / 10; Console.println(digits[2]);Console.println(digits[1]);Console.println(digits[0]);
效果
一气声明多个数据格
数组声明及创建
标准格式
<数组变量声明> = <数组创建>; <元素类型>[] <数组变量名> = new <元素类型>[<数组尺寸>];
int[] digits = new int[3];
兼容格式
<元素类型> <数组变量名>[] = new <元素类型>[<数组尺寸>];
int digits[] = new int[3];
默认值
通过 new
创建的数组, 每个数据格里都是该类型的默认值
类型 | 默认值 |
---|---|
int | 0 |
double | 0.0 |
boolean | false |
元素Elements
管数组里的每个变量叫元素
索引Index
数组使用索引定位数据格
格式
1<数组名>[<索引值>]
样例
1 2 3 4 5 // 赋值digits[2] = number % 10; // 取值Console.println(digits[2]);
索引范围
索引值范围从 0 开始 到 尺寸 - 1
数组越界
1 2!3!int[] digits = new int[5];System.out.println(digits[5]);System.out.println(digits[-1]);
访问越界的索引会导致运行时报错
强类型数组
数组里的每个元素的类型都是一样的
1!digits[0] = 3.7;
数组字面量
格式
{<元素字面量1>, <元素字面量2>, ..., <元素字面量n>}
样例
int[] digits = {2, 7, 3, 8, 4};
长度不可改
一旦创建时确定了数组的长度, 之后就不能改
如果需要, 只能造一个新的
1 2 3 int[] arr1 = new int[3];...int[] arr2 = new int[5];
一维数组 和 条件语句 的关系
使用前
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int number = Console.readInt(); String code = "";switch (number) { case 0: code = "-----"; break; case 1: code = ".----"; break; case 2: code = "..---"; break; case 3: code = "...--"; break; case 4: code = "....-"; break; case 5: code = "....."; break; case 6: code = "-...."; break; case 7: code = "--..."; break; case 8: code = "---.."; break; case 9: code = "----."; break;}Console.println(code);
使用后
1*2*3 4 5*6 7 String[] codes = {"-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----."}; int number = Console.readInt();String code = codes[number]; Console.println(code);
特性
分支结构的判断是一个变量
值是连续的
for 语句for Statements
作用
用于机械式重复一段代码
案例对比
使用前
1 2 3 4 String name = "ZZAX";Console.println(name);Console.println(name);Console.println(name);
使用后
1 2*3 4*String name = "ZZAX";for (int i = 0; i < 3; i++) { Console.println(name);}
语法
for (<初始化>; <维持条件>; <改变>){ <statements> }
维持条件部分 必须为 布尔值表达式
执行顺序
1 for (2; 3; 4){ 5 } 6
1 23 543 543 543 ... 543 6
3 有没有可能不执行 ?
一定会执行
可能不执行
4 有没有可能不执行 ?
一定会执行
可能不执行
5 有没有可能不执行 ?
一定会执行
可能不执行
标准 for 语句
一般
for (int i = 3; i > 1; i--){ ... }
标准
for (int i = 0; i < <次数>; i++){ <statements> }
唯一可以变的,就是 i
的名字,和 次数。
利用 i 值
1 2 3 < < <for (int i = 0; i < 3; i++) { Console.println(i);}012
for 语句 编写技巧
案例
输出 9 - 0
先写出不循环的版本
1 2 3 4 5 6 7 8 9 Console.println(9);Console.println(8);Console.println(7);Console.println(6);Console.println(5);Console.println(4);Console.println(3);Console.println(2);Console.println(1);
准备模板
1 2 3 for(int i = 0; i < <次数>; i++) { <statements>}
填次数
1*2 3 for(int i = 0; i < 9; i++) { <statements>}
填相同
相同
1Console.println(<不同>);
填进去
1 2*3 for(int i = 0; i < 9; i++) { Console.println(<不同>);}
找规律 填公式
数据
v: 9 8 7 6 5 4 3 2 1 i: 0 1 2 3 4 5 6 7 8
规律
v = 9 - i
填进去
1 2+3*4 for(int i = 0; i < 9; i++) { int value = 9 - i; Console.println(value);}
挑战
输出 1 3 5 7 9
for 语句 x 变量作用域
案例
代码
1 2 3 4 5 for(int i = 0; i < 3; i++) { int value = 3 - i; Console.println(value);}Console.println("end");
人工内存
Line io 1.1 0 1.2 | = true 2 | 3 3 | | < 3 4 | x 1.3 1 1.2 | = true 2 | 2 3 | | < 2 4 | x 1.3 2 1.2 | = true 2 | 1 3 | | < 1 4 | x 1.3 3 1.2 | = false 4 x 5 < end i value
规则
语句头
for 语句头的初始化部分的 变量 在最后一次碰到回 大括号的时候死
循环期间一直保留
语句内
for 语句里的 变量 每次撞到 回大括号 都死一次
每次循环都是新的
注意
在 for 语句里 可以用到的变量有
for 语句外面的
for 语句头里声明的
for 语句里声明的
for 语句 x 数组
使用前
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int number = Console.readInt(); int[] digits = new int[3]; digits[0] = number % 10;number = number / 10; digits[1] = number % 10;number = number / 10; digits[2] = number % 10;number = number / 10; Console.println(digits[2]);Console.println(digits[1]);Console.println(digits[0]);
使用后
1 2 3 4 5 6 7 8 9 10 11 12 int number = Console.readInt(); int[] digits = new int[3]; for (int i = 0; i < 3; i++) { digits[i] = number % 10; number = number / 10;} for (int i = 0; i < 3; i++) { Console.println(digits[2 - i]);}
循环控制
循环 内嵌 if 语句
可以内嵌 if 语句, 实现循环时达到分支效果
1 2 3 4 5 for (...){ if (...) { }}
挑战
基于下面的代码。写 循环输出
1 2 int[] arr = {6, 7, 3, 8, 4};// todo
使得输出
6, 7, 3, 8, 4
循环 与 boolean 运算 做假设验证
1 2 3 4 5 6 boolean test = false;for (...){ if (...) { test = true; }}
特性
只有每次循环,if
语句条件都不成立时,test
才会是 false
假设一个很难证明的
条件内赋值一个很好推翻的
挑战
检测数组里是否有 0,输出 true
或者 false
break 控制
立刻停止下面语句, 跳出循环
一般内嵌在条件语句里
代码
1 for (2; 3; 4){ 51 if (52) { break; } 53 } 6
执行顺序
1 2 3 51 52 53 4 3 51 52 break 7
continue 控制
立刻停止下面语句, 尝试下次循环
一般内嵌在条件语句里
代码
1 for (2; 3; 4){ 51 if (52) { continue; } 53 } 6
执行顺序
1 2 3 51 52 53 4 3 51 52 continue 4 3 51 52 53 4 3 7
早退出Early Exit
输出有几个 不是 0 的数
使用前
1 2 3 4 5 6 7 8 int[] arr = {6, 7, 3, 8, 4};int count = 0;for (int i = 0; i < arr.length; i++) { if (arr[i] != 0) { count++; }}Console.println(count);
使用后
1 2 3 4*5*6 7+8 9 int[] arr = {6, 7, 3, 8, 4};int count = 0;for (int i = 0; i < arr.length; i++) { if (arr[i] == 0) { continue; } count++;}Console.println(count);
效果
使得主逻辑的代码 的缩进 减少1个
字面量规范
使用原值
代码中 如果有 计算出来的字面量, 那么需要写是怎么计算的
使用前
1 2 3 4 5 6 7 8 int[] arr = {6, 7, 3, 8, 4}; for (int i = 0; i < 5; i++) { Console.print(arr[i]); if (i != 4) { Console.print(", "); }}
使用后
1 2 3 4 5*6 7 8 int[] arr = {6, 7, 3, 8, 4}; for (int i = 0; i < 5; i++) { Console.print(arr[i]); if (i != 5 - 1) { Console.print(", "); }}
为业务值定义变量
使用前
1 2 3 4 5 6 7 8 int[] arr = {6, 7, 3, 8, 4}; for (int i = 0; i < 5; i++) { Console.print(arr[i]); if (i != 5 - 1) { Console.print(", "); }}
使用后
1 2+3*4 5*6 7 8 int[] arr = {6, 7, 3, 8, 4};int size = 5;for (int i = 0; i < size; i++) { Console.print(arr[i]); if (i != size - 1) { Console.print(", "); }}
注意
引用变量
任何值 如果能从已知变量中计算出来, 那么就使用 已知变量
使用前
1 2 3 4 5 6 7 8 int[] arr = {6, 7, 3, 8, 4}; for (int i = 0; i < 5; i++) { Console.print(arr[i]); if (i != 5 - 1) { Console.print(", "); }}
使用后
1 2 3*4 5*6 7 8 int[] arr = {6, 7, 3, 8, 4}; for (int i = 0; i < arr.length; i++) { Console.print(arr[i]); if (i != arr.length - 1) { Console.print(", "); }}
最终效果
程序中只能出现 业务数据 和 -1, 0, 1, 2
原始数据值 只能出现一次
while 语句while Statements
案例
随机生成一个 1 - 9 之间的奇数
1 2 3 4 5 int number;do { number = new Random().nextInt(10); Console.println(number);} while (number % 2 == 0);
用途
用于执行不确定次数的重复
while
语法
while (<condition>) { <statements> }
while
执行顺序
1 while (2) { 3 } 4
1 2 32 32 ... 32 4
3 有没有可能不执行
一定会执行
可能不执行
do while
语法
do { <statements> } while (<condition);
do while
执行顺序
1 do { 2 } while (3) 4
1 23 23 ... 23 4
2 有没有可能不执行
一定会执行
可能不执行
while 循环控制
死循环
1 2 3 while(true) { ...}
跳出循环
1 2 3 4 5 6 7 while(true) { ... if (...) { break; } ...}
其它
while 里 也可以写 continue
while 语句 编写技巧
案例
< < > < < < > < < < > <查询余额请按 1结束请按 91您的余额为 100 元查询余额请按 1结束请按 91您的余额为 100 元查询余额请按 1结束请按 99再见
原始代码
写出非循环版本
1 2 3 4 5 6 7 8 9 10 11 12 Console.println("查询余额请按 1");Console.println("结束请按 9");Console.readInt();Console.println("您的余额为 100 元");Console.println("查询余额请按 1");Console.println("结束请按 9");Console.readInt();Console.println("您的余额为 100 元");Console.println("查询余额请按 1");Console.println("结束请按 9");Console.readInt();Console.println("再见");
死循环
找到重复单元,套在 死循环里
1*2 3 4 5 6*7 while(true) { Console.println("查询余额请按 1"); Console.println("结束请按 9"); Console.readInt(); Console.println("您的余额为 100 元");}Console.println("再见");
找出口
找到跳出情况,写 if break
1 2 3 4*5+6+7+8 9 10 while(true) { Console.println("查询余额请按 1"); Console.println("结束请按 9"); int option = Console.readInt(); if (option == 9) { break; } Console.println("您的余额为 100 元");}Console.println("再见");
校验
运行,测试次数是否正确
while 语句 死循环 简化 一般 while 语句
规则
如果 if break
在 最后一句,可以转为 do while condition
如果 if break
在 第一句,可以转为 while condition
其它情况,不能简化
注意:转换时,逻辑需要反转
案例
使用前
1 2 3 4 5 6 7 8 Console.println("我说鸡蛋,你说要");while(true) { Console.println("鸡蛋"); String command = Console.readLine(); if (!command.equals("要")) { break; }}
使用后
1 2+3 4 5*6*Console.println("我说鸡蛋,你说要");Stirng command;do { Console.println("鸡蛋"); command = Console.readLine();} while (command.equals("要"));
注意:判断挪到 while condition 区域时,可能需要提高变量的作用域
循环 语句 对比
while
和 do while
的区别
while
先检查,再执行,有可能不执行
do while
先执行,再检查,保障至少执行一次
while
和 for
的区别
for
用于 知道 次数的循环 更贴切
while
用于 不知道 次数的循环 更贴切
for
与 while
互转
for
转 while
1 for(2; 3; 4) { 5 } 6
可转为
1 2 while(3) { 5 4 } 6
前提是里面没有 continue 或者 break
案例分析
输出一个数组里的值,遇到 0 就停,不输出 0
程序会因为 不确定的 0 的出现 而停止
程序也会因为 确定的 元素结束 而停止
for 版本
1 2 3 4 5 6 7 8 9 int[] arr = {6, 7, 0, 8, 4}; for (int i = 0; i < arr.length; i++) { if (arr[i] == 0) { break; } else { Console.println(arr[i]); }}
while 版本
1 2 3 4 5 6 7 8 9 10 11 12 13 int[] arr = {6, 7, 0, 8, 4};int i = 0;while (true) { if (arr[i] == 0) { break; } else { Console.println(arr[i]); i++; if (i == arr.length) { break; } }}
for x 早推出 版本
1 2 3 4 5 6 7 8 int[] arr = {6, 7, 0, 8, 4}; for (int i = 0; i < arr.length; i++) { if (arr[i] == 0) { break; } Console.println(arr[i]);}
while x 早推出 版本
1 2 3 4 5 6 7 8 9 10 11 12 int[] arr = {6, 7, 0, 8, 4};int i = 0;while (true) { if (arr[i] == 0) { break; } Console.println(arr[i]); i++; if (i == arr.length) { break; }}
for x 断义 版本
1 2 3 4 5 int[] arr = {6, 7, 0, 8, 4}; for (int i = 0; i < arr.length && arr[i] != 0; i++) { Console.println(arr[i]);}
while x 断义 版本
1 2 3 4 5 6 7 int[] arr = {6, 7, 0, 8, 4}; int i = 0;while (i < arr.length && arr[i] != 0) { Console.println(arr[i]); i++;}
存储介质
一些练习中,你需要好好考虑,使用什么存储介质(专业名词叫 数据结构)更恰当
整数补 0 循环版
Q2 E02
使用 int 存储输入数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int number = Console.readInt(); // 探测 number 的位数 int digitSize = ... // 计算 前面需要补0 的个数int leadingZeroSize = ... // 打印 前面的 0 for(int i = 0; i < leadingZeroSize; i++) { ...} // 打印 原始数据Console.println(number);
使用 int 数组 存储输入的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 int limit = 4;int number = Console.readInt(); // 存入 数组int[] digits = new int[limit];for (int i = 0; i < limit; i++) { int index = limit - i - 1; ...} // 打印 出来for (int i = 0; i < limit; i++) { Console.print(digits[i]);}