Java基础的循环嵌套和数组
1. 循环嵌套
循环嵌套就是一个循环套在一个或多个循环上(俗称“套娃”),下面通过一个案例来展示循环嵌套。
1 public class Demo01 { 2 public static void main(String[] args) { 3 for (int i = 0; i <=3 ; i++) { 4 for(int j = 0; j<=3;j++){ 5 System.out.println("你好吗"); 6 } 7 } 8 } 9 }
循环嵌套执行顺序是:内部执行完后,再执行外部一次。
外层循环m次,内层循环n次,实际上循环了m*n次
建议:
实际开发中,不要嵌套太深,嵌套一次就够了(不然容易把自己绕晕)。
练习一:
******
******
******
******
使用for循环嵌套打印上面的内容。
思路:
通过观察发现一共有四行,有六列的*,所以可以考虑到使用循环嵌套的方式实现
i = 0时,i<4为true,进入循环 for(int j = 0; j<6 ;i++){ //j的取值从0到5,执行一轮打印* System.out.print("*"); } i = 1时,i<4为true,进入循环 for(int j = 0; j<6 ;i++){ //j的取值从0到5,执行一轮打印* System.out.print("*"); } i = 2时,i<4为true,进入循环 for(int j = 0; j<6 ;i++){ //j的取值从0到5,执行一轮打印* System.out.print("*"); } i = 3时,i<4为true,进入循环 for(int j = 0; j<6 ;i++){ //j的取值从0到5,执行一轮打印* System.out.print("*"); } 直到i = 4时,i<4为false跳出整个循环
代码:
1 public class Demo01 { 2 public static void main(String[] args) { 3 for (int i = 0; i < 4; i++) { 4 for (int j = 0; j < 6; j++) { 5 System.out.print("*"); 6 } 7 System.out.println(); 8 } 9 } 10 }
练习二:
需求:在控制台使用 * 打印出这个图案
*
**
***
****
思路:
通过观察发现: 第一行时输出一个 int i=1时,i <=4为true,执行一轮循环 for(int j = 1;j<=i;j++){ //j取值1,打印一个* System.out.print("*"); } 第二行时输出二个 int i=2时,i <=4为true,执行一轮循环 for(int j = 1;j<=i;j++){ //j取值1到2,打印两个* System.out.print("*"); } 第三行时输出三个 int i=3时,i <=4为true,执行一轮循环 for(int j = 1;j<=i;j++){ //j取值1到3,打印三个* System.out.print("*"); } 第四行时输出四个 int i=2时,i <=4为true,执行一轮循环 for(int j = 1;j<=i;j++){ //j取值1到4,打印四个* System.out.print("*"); } 所以根据这些规律我们可以想到内层循环的个数与外层循环有关的
代码:
1 public class Demo01 { 2 public static void main(String[] args) { 3 for (int i = 1; i <= 4; i++) { 4 for (int j = 1; j <= i; j++) { 5 System.out.print("*"); 6 } 7 System.out.println(); 8 } 9 } 10 }
1.1 跳出语句break、continue关键字
当我们遇到死循环时,或在一个特定的条件下跳出循环时我们可以运用break和continue关键字来实现
- break作用:跳出并结束当前的循环(注意一个break只能结束一层循环)
- continue作用:结束本轮循环、跳转到下一轮循环
演示break的用法:
1 public class Demo01 { 2 public static void main(String[] args) { 3 /* 4 案例: 5 当你被妈妈罚去洗碗5天 6 结果到第3天时,妈妈心软了不罚你了*/ 7 //使用循环,循环输出5次代表洗碗5次 8 for(int i=1;i<=5;i++){ 9 System.out.println("第"+i+"天洗碗"); 10 //第3天后妈妈心软不罚你洗碗 11 //所以到第3天后不再执行循环,所以使用break结束循环 12 if(i==3){ 13 break; 14 } 15 } 16 } 17 }
演示continue的用法:
1 public class Demo01 { 2 public static void main(String[] args) { 3 /* 4 需求: 5 当你被妈妈罚去洗碗5天 6 结果到第3天时,妈妈心软了不罚你了 7 当到第4天发现你太懒了决定继续罚你 8 */ 9 //使用循环,循环输出5次代表洗碗5次 10 for(int i=1;i<=5;i++){ 11 //第3天后妈妈心软不罚你洗碗, 12 //但是当到第4天发现你太懒了决定继续罚你,这里就需要用continue 13 if(i==3){ 14 continue; 15 } 16 System.out.println("第"+i+"天洗碗"); 17 } 18 } 19 }
注意:
break和continue使用的场景是不相同的。
①break是用于循环语句和分支结构的switch中,对于其他结构是不可以加break,否则会编译不通过的。
②continue是只能用于循环语句中,并且不能与break同时使用的,对于其他结构也是不能加continue的,否则会编译不通过的。
2. 随机数
在Java中随机数提供两种方法。
方法一:Math类的random()的调用,会返回一个[0,1)范围的一个double型值
方法二:使用Random类,创建一个实例可以获得不同类型的随机数有整数nextInt()、长整数nextLong()、单精度nextFloat()、双精度nextDouble()
举个例子:
1 import java.util.Random; 2 3 public class Demo03 { 4 public static void main(String[] args) { 5 //方式一:使用Math类中的random() 6 double a = Math.random();//生成一个[0,1)的浮点型随机数 7 //在生成random后面乘以10来扩大10倍 8 double b = Math.random()*10;//生成一个[0,10)的浮点型随机数 9 //在生成random后面也可以加上10,让步长增加10 10 double c = Math.random() + 10;//生成一个[10,11)的浮点型随机数 11 //方式二:使用Random类 12 //①生成一个随机对象 13 Random random = new Random(); 14 //②通过随机对象去生成一个随机数 15 int i = random.nextInt();//生成一个[0,1)的整型随机数 16 //在生成int随机数时可以在括号里面写入数字,用于扩大数字倍数 17 int j = random.nextInt(10);//生成[0,10)的整型随机数 18 //在生成int随机数时可以加上数字,让步长增加数字量 19 int z = random.nextInt() + 1;//生成[1,2)的整型随机数 20 } 21 }
练习:
需求:
随机生成一个1-100之间的数据,提示用户猜测,猜大提示过大,猜小提示过小,直到猜中结束游戏
思路:
1. 先要生成一个[1,100]的随机数,需要运用random来实现 2. 用户是一直猜直到猜中为止,所以需要死循环,当猜中时跳出循环 3. 在死循环中,用户需要不断输入值,这时要用到scanner完成输入操作,对用户输入的值与随机数进行比较,大了要进行提示,小了也要进行提示
代码:
1 import java.util.Random; 2 import java.util.Scanner; 3 4 public class Test08 { 5 public static void main(String[] args) { 6 Scanner sc = new Scanner(System.in); 7 Random random = new Random(); 8 int i = random.nextInt(100) + 1; 9 while(true){ 10 System.out.print("请输入一个数字:"); 11 int j = sc.nextInt(); 12 if(j == i){ 13 System.out.println("恭喜猜对了"); 14 break; 15 } 16 if(j >i){ 17 System.out.println("过大"); 18 } 19 if(j < i){ 20 System.out.println("过小"); 21 } 22 } 23 } 24 }
3. Java数组
3.1 了解Java数组
在讲数组之前,我们需要了解什么是数组。数组相当于一个垃圾桶,而垃圾桶也是分为可回收垃圾、不可回收垃圾、有毒垃圾等,不同类型的垃圾是要扔到对应的垃圾桶对吧,而在数组中,不同类型的数据,也是要对应数据类型去存放的,而垃圾桶的名称就相当于数组的名称。
而变量与数组的功能类似,为什么推荐是使用数组更好呢?
原因是:
如果要用变量来实现是这样子的: String name1 = "张三"; String name2= "李四"; String name3 = "王五"; String name4 = "赵六"; String name5 = "吴七"; .............................. String name100 = "李华"; 管理这些变量会显得十分繁琐,太麻烦了 而如果使用数组是这样子的: String[] arr ={"张三","李四",............,"李华"}; 直接一行代码搞定,代码简介逻辑清晰
这样一对比感觉是不是使用数组会更加好。
3.2 数组的初始化
数组的初始化分两种静态初始化和动态初始化
- 静态初始化标准格式
数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3,元素4};
比如:
int [] arr =new int[]{1,2,3,4,5,6,7,8,9};
- 静态初始化简化格式
数据类型 [] 数组名 = {元素1,元素2,元素3,元素4};
比如:
int [] arr = {1,2,3,4,5,6,7};
- 动态初始化格式
程序员只决定数组元素的长度,系统分配元素初始值
格式:数据类型[] 数组名 = new 数据类型[数量];
例子:String [] str = new String[5];
数据类型的默认值:
3.3 数组元素的访问
我们已经知道数组和数组的初始化方式,现在我们来学习一下如何访问数组中的元素?
数组访问需要知道数组中索引的概念。
索引
数组中每个元素都有索引值,而数组中的索引值是从0开始的,因为索引值是计算数组元素在地址位置的偏移量。
举个例子:
除了访问数组中的元素,我们也可以获取元素的个数。
//访问数组中的长度方法:数组名.length
比如:
int[] arr={1,2,3,4,5,6,3,2};
System.out.print(arr.length);//输出数组的长度
//因为数据索引从0开始,所以在数组最大索引位置为arr.length-1
循环遍历访问数组
数组的长度知道怎么求,数组中访问数据中索引也明白了,我们就可以使用循环的方式遍历访问数组。
访问数组可以直接使用索引的方式,将数组中的元素进行访问或修改
int arr ={1,2,3,4,5,6}; //将数组中索引为0的元素修改为5 arr[0]=5; //访问数组中索引为0的元素 System.out.print(arr[0]);
通过循环的方式访问数组中所有元素:
1 public class Demo { 2 public static void main(String[] args) { 3 int[] arr={1,3,4,2,3,4}; 4 for (int i=0;i<arr.length;i++){ 5 System.out.print(arr[i]+"\t"); 6 } 7 } 8 }
数组的循环遍历我们可以使用Java新特性foreach方法
代码:
/*
foreach格式为:
for(数据类型 变量名 : 数组名){
System.out.print(变量名);
}
注意一点:数据类型要与数组中的数据类型一致才行
*/
int[] arr= {8,4,2,1,23,344,12};
for (int i: arr) {
System.out.print(i+"\t");
}
3.4 一维数组的内存解析
我们来讲讲底层是如果存放数组的。而讲到底层我们想要了解一下Java中内存结构划分。
内存分为5个部分:程序计数器、虚拟机栈、本地方法栈、堆、方法区。
举个例子:
目前数组相关的内存结构:(比如 int [] arr = new int [] {1,2,3})
(1) 虚拟机栈:用于存放方法中声明的变量。比如:arr
(2) 堆:用于存放数组的实体(即数组中的所有元素,占用一块连续的空间)
4. 数组中的经典例题
4.1 查询数组中的最大和最小值
查询数组中的最大和最小值方法都是一样的,可以用到擂台法。
擂台法的意思是:先将第一个作为最大或最小值,然后不断循环遍历,如果发现我选出来当擂台里的那个值小于或大于数组中遍历的元素时,则进行取代擂台上的值,直到循环遍历。
备注:求最大值的方法我用红色来标记,求最小值的方法我用蓝色来标记。
案例:
1 //需求: 2 //在int[] arr= {10,23,43,23,56,43,12,56,67,32};中找出最小的数 3 public class Test05 { 4 public static void main(String[] args) { 5 int[] arr= {10,23,43,23,56,43,12,56,67,32}; 6 //选第一个上擂台 7 int temp=arr[0]; 8 for (int i = 0; i < arr.length; i++) { 9 //如果在数组中有比擂台上的值小时 10 if(temp>arr[i]){ 11 //那就将数组中更小的数,当作擂台上的值 12 temp=arr[i]; 13 } 14 } 15 System.out.println("最小 = " + temp); 16 } 17 }
4.2 为数组排序(选择排序法)
选择排序法的核心就是不断循环遍历进行比较把最小的数放到它对应的索引位置
举个例子:
1 //需求 2 //将数组中的元素按照从大到小排序 3 public class Test05 { 4 public static void main(String[] args) { 5 int[] arr= {8,4,2,1,23,344,12}; 6 //外层循环,将每轮最小的数放在对应索引位置 7 for (int j=0;j<arr.length;j++) { 8 //开始位置要从 j+1开始,因为在前面的数已经排好序,就没必要再比较一次 9 for(int i=j+1;i<arr.length;i++){ 10 //先将第一个数作为擂台值,然后里面for循环进行比较 11 //如果发现擂台上的值小于数组循环遍历值,则交换位置 12 if(arr[j]<arr[i]){ 13 int temp=arr[j]; 14 arr[j]=arr[i]; 15 arr[i]=temp; 16 } 17 } 18 } 19 } 20 }
4.3 查询某个数是否在数组中
思路:
①查找某个数是否在数组中,我们就要想让用户输入需要查询的数据
②将用户输入的数据存储起来,并将这个数与数组中的数进行循环比较
③我们可以用一个布尔类型的值,来判断是否存在这个值,先将这个值设为false。
④如果存在这个值就没必要继续循环遍历了,直接break并将布尔类型的值赋为true。否则如果不存在则保持不变。
⑤最后将布尔类型的值进行判断,如果为true则存在,为false则不存在
举个例子:
1 //需求 2 //用户输入一个数,然后判断这个数是否存在数组中 3 4 import java.util.Scanner; 5 6 public class Test04 { 7 public static void main(String[] args) { 8 int[] arr= {8,4,2,1,23,344,12}; 9 Scanner sc = new Scanner(System.in); 10 System.out.print("请输入一个数"); 11 int a = sc.nextInt(); 12 boolean flag=false; 13 for(int i=0;i<arr.length;i++){ 14 if(a == arr[i]){ 15 flag = true; 16 break; 17 } 18 } 19 if(flag){ 20 System.out.println("存在这个数这数组中"); 21 }else{ 22 System.out.println("不存在这个数在数组中"); 23 } 24 } 25 }
4.4 数组的反转
数组反转的概念:
数组中将第一个数和最后一个数进行交换,第二个数和倒数第二个数进行交换以此类推。
思路:
首先数组的反转只需要前面一部分反转就可以了,后面那一部分再反转就会变成原来的样子 然后数组的反转我们需要明白两个数之间如何交换。 两个数之间的交换比如: a = 10 与 b = 20之间进行交换 需要用到第三方变量 temp来临时存储一个变量的值 代码: int temp = a; a = b; b = temp; 这样就完成数与数之间的交换操作。 两个数之间交换明白后,需要学习如何进行数组反转。 首先需要找规律看哪两个数之间进行交换。 例子:int [] arr={1,2,3,4,5,6,7,8}; ①当 i=0时: 第一个元素arr[0] 和 倒数第一个元素arr[arr.length-1]进行交换 ②当 i=1时: 第二个元素arr[1] 和 倒数第二个元素arr[arr.length-1-1]进行交换 ③当 i=2时: 第三个元素arr[2] 和 倒数第三个元素arr[arr.length-1-2]进行交换 从这里可以看出如果当 i=n时(发现最后减的数与i是有关系的)
第n个元素arr[n] 和 倒数第n个元素arr[arr.length-1-n]进行交换
这样就可以实现数组的反转。
代码:
1 public class Test01 { 2 public static void main(String[] args) { 3 int [] arr={1,2,8,4,5,7,4}; 4 for(int i=0;i<arr.length/2;i++){ 5 int temp=arr[i]; 6 arr[i]=arr[arr.length-1-i]; 7 arr[arr.length-1-i]=temp; 8 } 9 System.out.println("反转后的数组:"); 10 for (int i: arr) { 11 System.out.print(i+"\t"); 12 } 13 } 14 }
4.5 数组的二分查找
数组的二分查找是一个十分快速的查找方式,因为它每次查询直接干掉一半的数据时间复杂度为O(log2n)
但是注意数组二分查找的前提是:数组是按照顺序排序的,无序的不可以
思路:
①需要确定数组中最小值的索引和最大值的索引。
②通过最大值和最小值,确定中间值
③将需要查询的数与数组中间值索引的数进行比较
(1)如果刚好相等时,就进行输出“数据在数组中”,并break
(2)如果查询的数据比中间值索引的数大时,将最小值赋值为中间值+1
(3)如果查询的数据比中间值索引的数小时,将最大值赋值为中间值-1
④最后如果循环中最小值小于等于最大值不满足时,跳出循环,并输出“数据不在数组中”
代码:
1 public class Test02 { 2 public static void main(String[] args) { 3 int [] arr={1,2,3,4,5,6,7,8,9}; 4 int min=0; 5 int max=arr.length-1; 6 int num=0; 7 while(min<=max){ 8 int mid=(min+max)/2; 9 if(arr[mid]>num){ 10 max=mid-1; 11 } else if (arr[mid]<num) { 12 min=mid+1; 13 }else{ 14 System.out.println("这个数存在"); 15 break; 16 } 17 } 18 if(min>max){ 19 System.out.println("这个数不存在"); 20 } 21 } 22 }
5. Arrays工具类
Arrays工具类是Java中的java.util.Arrays包下的一个类,而这个类封装了许多数组方法,我们可以通过这个包去直接调用相关的方法。
常用的方法有:
①排序:sort()
②二分查找:binarySearch()
③数组转换成字符串:toString()
④复制并扩容方法:copyOf()
5.1 排序方法---sort
语法:Arrays.sort(数组名)
举个例子:
1 import java.util.Arrays; 2 3 public class Test { 4 public static void main(String[] args) { 5 int [] arr ={2,8,4,7,9,4,1,7,5,2,4}; 6 //sort(数组名) 7 Arrays.sort(arr); 8 for (int i: arr) { 9 System.out.print(i+"\t"); 10 } 11 } 12 }
效果展示:
可以看见直接帮你排好序,底层使用的是快速排序算法来实现。
5.2 二分查找---binarySearch
语法:Arrays.binarySearch(数组名,需要查询的值)
注意:这个方法有返回值,返回值类型为int,当返回值小于0时说明查询的数据不在数组中,如果返回值大于0说明查询的数据索引值为返回值。
举个例子:
1 import java.util.Arrays; 2 3 public class Test { 4 public static void main(String[] args) { 5 int [] arr ={1,2,2,4,4,4,5,7,7,8,9}; 6 //binarySearch(数组名,查询的数据) 7 int index = Arrays.binarySearch(arr, 5); 8 if(index<0){ 9 System.out.println("这个数不在数组中"); 10 }else { 11 System.out.println("这个数在数组中的第"+(index+1)+"位"); 12 } 13 } 14 }
效果展示:
5.3 数组转化为字符串---toString()
语法:Arrays.toString(数组名)
返回的值是一个字符串
举个例子:
1 import java.util.Arrays; 2 3 public class Test { 4 public static void main(String[] args) { 5 int [] arr ={1,2,2,4,4,4,5,7,7,8,9}; 6 //toString(数组名) 7 System.out.println(Arrays.toString(arr)); 8 } 9 }
效果展示:
5.4
1 import java.util.Arrays; 2 3 public class Test { 4 public static void main(String[] args) { 5 int [] arr ={1,2,2,4,4,4,5,7,7,8,9}; 6 //copyOf(旧的数组名,新的数组长度) 7 int[] arr1 = Arrays.copyOf(arr, arr.length + 1); 8 System.out.println(Arrays.toString(arr1)); 9 } 10 }
效果展示:
注意:
设置新数组长度时,如果长度比旧数组的长度要短时,就只截取长度的位置为止结束。
而如果长度比旧数组的长度要长时,后面空出来的索引位置里面的值就取默认值。