数组与循环流程控制
数组与循环流程控制
1 数组
1.1 什么是数组
数组是内存中的连续的类型一致的存储单元,用于存储数据类型一致的一组数据利用数组可以实现一个变量管理一组数据。
Java的数组两大类型:
- 基本类型数组
- 引用类型数组
1.2 基本类型数组
语法:
数据类型【】数组变量=new 数据类型【长度】
基本类型数组语法:
-
数组类型是引用类型,数组变量是引用类型变量
-
数组是一个对象,数组对象中连续存储着数组元素
-
创建数组对象时候需要指定数组长度
-
数组元素有默认“0”值:
a.整数:0
b.浮点数:0:0
c.布尔类型:false
d.字符:编号为0的字符,此字符是一个控制字符,直接打印输出时候不可见!
int[] arr=new int[4];//声明数组
System.out.println(arr[0]);//读取数组元素的值
arr[0]=8;//修改数组元素的组
arr[1]=10;
arr[2]=30;
arr[3]=100;
//arr[4]=10;//超值
System.out.println(arr[0]);
System.out.println(arr.length);//获取数组的长度
//数组相当于储存了一组变量,每个元素都是一个变量
int n=arr[2]+arr[2]*10;
System.out.println(n);
//利用length可以读取数组长度
System.out.println(arr.length);
double[] arr1=new double[3];
System.out.println(arr1[0]);
arr1[0]=35;
System.out.println(arr1[0]);
//使用已知数数据直接初始化数组元素
int[] arr2=new int[] {9,19,23,65,8};
// 0, 1, 2, 3, 4
int[] arr4;
//arr4= {5,2,4,5};编辑错误
arr4=new int[] {5,2,4,5};
//char 数组
char[] chs=new char[5];//每个元素存储是编号为0的字符
System.out.println(chs[0]);//编号为0的字符是控制字符,输出基本没有效果
System.out.println((int)chs[0]);//0
/*
* 1.使用长度初始化;数组元素未知 或者 是数组元素非常多
* 2。使用元素初始化;适用元素已知的情况
* 简写的使用元素化;适用元素已知的情况,必须是声明数组直接初始化
*/
使用元素初始化数组:当已经预知数组元素时候采用这个方式更加简便
int[] arr=new int[]{5,6,8};
可以简化为:
int[] arr={5,6,8};//只能用在声明变量直接初始化
1.3 引用类型数组
引用类型数组的每个元素是一个引用类型变量,目的是管理一组对象。
public class Arraydemo02 {
public static void main(String[] args) {
/*/
* 测试引用类型数组
*/
Cell[]arr=new Cell[4];
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
System.out.println(arr[3]);
arr[0]=new Cell(2,3);
arr[1]=new Cell(4,9);
arr[2]=new Cell(10,8);
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
System.out.println(arr[3]);
System.out.println(arr[0].row+","+arr[0].col);
}
}
class Cell{
int row;
int col;
public Cell(int row,int col) {
this.row=row;
this.col=col;
}
}
2 for循环流程控制
多次重复执行一个程序单元使用循环流程控制实现。Java中包含三种循环结构:for while do-while
2.1 for循环流程控制
for循环四个要素:
- 初始化
- 循环条件(结束)
- 递增
- 循环体
for循环工作流程:
for(int i=0; i<3; i++){
System.out.println(i);
}
/*
* 利用for循环实现1+2+。。。+100
* 利用等差数列求和公式验证;(1+100)*100/2=5050
*/
int sum=0;
// 初始 循环条件 递增
for(int i=1;i<=100;i++) {
sum +=i;//循环体 sum=sum+i;
}
System.out.println(sum);
2.2 for遍历数组元素
/*
* 遍历数组元素(迭代数组);累加数组元素
*/
int[] arr= {5,8,12,5,8};
// 0,1,2,3,4
int sum=0;
for (int i=0;i<arr.length;i++) {
sum +=arr[i];
}
System.out.println(sum);
2.3 for循环特殊用法
/*
* 循环变量的作用范围
* i j k
*/
for(int i=0; i<=3; i++) {
//i=0 1 2 3
System.out.println(i+"-");
}
System.out.println();
for(int i=0; i<=4; i++) {
//i=0 1 2 3 4
System.out.println(i+"-");
}
//System.out.println(i);*//编辑错误,没有变量i
System.out.println();//4
//利用i实现两个循环接力处理
int i=0;
for ( ; i<=3; i++) {
//i=0 1 2 3
System.out.println(i+"-");
}
//System.out.println(i);//4
for( ; i<=5; i++) {
//i=4 5
System.out.println(i+"+");
}
System.out.println(i);//6
for循环可以省略循环条件,可利用break退出循环
for(int i=0; ; i++){
System.out.println(i);
if(i==10){
break;//退出循环
}
}
for循环可以省略递增表达式,可在循环体中控制循环变量的值,进而控制循环结束
for(int i=0; i<=10; ){
System.out.println(i++);
}
for循环可以省略全部的表达式,只留下循环体,为“死"循环,添加break语句结束循环
long timeout=System.currentTimeMillis()+1000;
for( ; ;) {
System.out.println("我爱java");
if(System.currentTimeMillis()>timeout) {
break;
}
}
System.out.println("Timeout");
逗号表达式:
- Java逗号也是运算符,多个表达式用逗号连接构成逗号表达式
- 本质上是将for循环表达式写成逗号表达式
for(int i=1, j=6; i<=6; i+=2; j-=2){
System.out.println("i,j=" + i + "," + j);
}
2.4 break语句
- break可用于循环语句或switch语句中
- break用于循环,可使程序终止循环而执行循环后面的语句,常常与条件语句一起使用
int sum=0;
for(int i=1;i<=100;i++) {
if (sum>4000) {
System.out.println(i);
break;
}
sum=sum+i;//sum +=i;q
}
System.out.println(sum);
2.5 continue语句
- continue只能用于循环中
- 作用为跳过循环体中剩余语句而执行下一次循环
/*
* continue 演示
* 跳过一百以内7的倍数和以7为结尾的数
*/
for(int i=1; i<=100; i++) {
//1,2,3,,,,,100
//i是7的倍数 i以7结尾
if(i%7==0||i%10==7) {
System.out.println("跳过:"+i);
continue;
}
System.out.println(i);
}
3 while和do...while
3.1 while 循环流程控制
不计次循环执行流程:
- 计算“循环条件”表达式的值
- 如果值为true则执行循环体;再判断“循环条件”表达式的值,如果为ture则继续执行循环体;知道“循环条件”为false时结束while循环。
- 两要素:
- 循环体
- 循环条件
- while(循环条件){
- 循环体;
- }
public class WhileDemo09 {
public static void main(String[] args) {
//摇色子,到出现:“豹子”时候停下来
int dice1=1;
int dice2=2;
int dice3=3;
Random random=new Random();
while(dice1!=dice2 ||dice2!=dice3) {
dice3=random.nextInt(7-1)+1;
dice2=random.nextInt(7-1)+1;
dice1=random.nextInt(7-1)+1;
System.out.println(dice1+","+dice2+","+dice3);
}
}
}
3.2 do...while循环流程控制
先执行循环体再计算循环条件表达式的值,如果为true,再次执行循环体,如此循环,知道循环体表达式的值为false为止。
案例:猜数字:
- 程序随机生成并存储一个100以内整数
- 用户输入一个整数,程序比较大小,直到用户猜对数字为止
public class DoehileDemo10 {
public static void main(String[] args) {
/*
* 猜数字游戏
*/
Scanner console=new Scanner(System.in);
int num=(int)(Math.random()*100);
System.out.println("开始猜猜吧");
int guess;
do {
guess=console.nextInt();//从控制台读取用户输入的数据
if(guess>num) {
System.out.println("猜大了");
}
if(guess<num) {
System.out.println("猜小了");
}
if(guess==num) {
System.out.println("恭喜你,猜对了");
}
}while(guess!=num);
}
}
3.3 比较while 和 do...while
- while结构:先“循环条件”后执行“循环体”,有可能循环体一次都不执行
- do...while结构:先执行“循环体”后执行“循环条件”,至少执行一次“循环体”
4 重构跑泡泡
4.1 利用数组存储一组泡泡
public class BallApp extends App{
Ball[] balls=new Ball[200];
public static void main(String[] args){
BallApp app=new BallApp();
app.start();
}
}
new Ball[100]不是创建了100个Ball对象,而是100个null变量,利用for循环初始化
public class BallApp extends App{
Ball[]balls=new Ball[200];
public BallApp() {
for(int i=0; i<balls.length; i++) {
balls[i]=new Ball();
}
}
public static void main(String[] args){
BallApp app=new BallApp();
app.start();
}
}
4.2 利用循环绘制,移动每个泡泡
public class BallApp extends App{
Ball[]balls=new Ball[200];
public BallApp() {
for(int i=0; i<balls.length; i++) {
balls[i]=new Ball();
}
}
public void painting(Graphics2D g) {
for(int i=0; i<balls.length; i++) {
balls[i].move();//让每个球球运动起来
balls[i].paint(g);
}
}
public static void main(String[] args){
BallApp app=new BallApp();
app.start();
}
}
4.3 解决”溜边“Bug
造成此问题的根本原因:浮点数运算不精确。
public class Ball {
double x;
double y;
int d;
int r;
int g;
int b;
Color color;
double offsetx;
double offsety;
public Ball() {
d=(int)(Math.random()*(30-2)+2);
x=Math.random()*(800-d);
y=Math.random()*(600-d);
r=(int)(Math.random()*256);
g=(int)(Math.random()*256);
b=(int)(Math.random()*256);
color=new Color(r,g,b);
offsetx=Math.random()*(6-1)*1;
offsety=Math.random()*(6-1)*1;
offsetx=Math.random()>0.5?offsetx : -offsetx;
offsety=Math.random()>0.5?offsety : -offsety;
}
public void move() {
x+=offsetx;
y+=offsety;
if(x>800-d) {
offsetx=-offsetx;
//System.out.println("碰到右边缘: "+x+","+d);
x=800-d;
}else if(y>600-d) {
offsety=-offsety;
//System.out.println("碰到下边缘: "+y+","+d);
y=600-d;
}else if(x<0) {
offsetx=-offsetx;
//System.out.println("碰到左边缘: "+x+","+d);
x=0;//解决“溜边”Bug
}else if(y<0) {
offsety=-offsety;
//System.out.println("碰到上边缘: "+y+","+d);
y=0;//解决“溜边”Bug
//System.out.println(x+","+y);
//System.out.print(offsetx+","+offsety);
}
}
public void paint(Graphics2D g) {
g.setColor(color);
g.fillOval((int)x,(int)y,d,d);
}
}
4.4 吃掉泡泡
功能设计:
- 由于是泡泡的功能,就在泡泡上面增加算法eat
- 由于当前泡泡吃掉(包含)目标泡泡,则当前泡泡直径必须大于被吃掉的泡泡,所以要先检查当前泡泡直径是否大于目标泡泡
- 理解勾股定理计算出两个圆心的距离,利用距离和半径和比较出是否包含关系
- 利用面积计算新圆的直径
重构Ball添加eat方法:
public boolean eat(Ball ball) {
double X=x, Y=y, D=this.d;//大球
double x=ball.x, y=ball.y, d=ball.d;//小球
//检查球的直径是否合理
if(d>D) {
return false;//直径不合理,不进行进一步比较
}
//利用勾股定理计算两个球之间的距离
double a=(X+D/2)-(x+d/2);
double b=(y+d/2)-(Y+D/2);
double c=Math.sqrt(a*a+b*b);
boolean eaten=c<D/2-d/2;
//如果发生吃了就进行两个圆的合并
if(eaten) {
//计算合并以后的圆面积
double R=D/2,r=d/2;
double area=Math.PI*R*R+Math.PI*r*r;
double rx=Math.sqrt(area/Math.PI);
this.d=(int)rx*2;//替换当前圆的直径
}
return eaten;
}
测试:
public class EatTest {
public static void main(String[] args) {
/*
* 对吃功能进行单元测试
*/
Ball ball1=new Ball();
Ball ball2=new Ball();
ball1.x=18;
ball1.y=28;
ball1.d=292;
ball2.x=207;
ball2.y=125;
ball2.d=100;
System.out.println(ball1.eat(ball2));//true
System.out.println(ball1.d);
}
}
4.5 数组的复制
复制API方法:
- System.arraycopy()
- Arrays.copyOf()
使用System.arraycopy()方法可以实现数组的复制,适合在已经存在的两个数组之间进行复制。
/*
* 数组的复制System.arratcopy()
*/
int[] src= {1,2,3,4,5,6,7,8,9,10};
// 0 1 2 3 4 5 6 7 8 9
int[] dest= {0,0,0,0,0,0,0,0,0,0};
// 0 1 2 3 4 5 6 7 8 9
//System.arraycopy(源数组,源数组中的位置,目标数组,目标数组中的位置,复制个数)
System.arraycopy(src, 1, dest, 1, 6);
for(int i=0; i<dest.length; i++) {
System.out.print(dest[i]+"");//0234567000
}
使用java.util.Arrays类的copyOf方法可以实现数组的复制。
特点:
- 生成的新数组是原始数组的副本
- newLength小于源数组,则进行截取
- newLength大于源数组,则用0或null进行填充
- 产生的新数组可以大于源数组的长度
public class CopyofDemo12 {
public static void main(String[] args) {
/*
* Arrsys.copyof 功能
*/
int[] arr= {3,1,5,7,1,3,7,8,9};
// 0 1 2 3 4 5 6 7 8
int[] arr1=Arrays.copyOf(arr,5);
for(int i=0; i<arr1.length; i++) {
System.out.print(arr1[i]+"");//31571
}
System.out.println();
}
}
4.6 删除被吃掉的泡泡
-
将球看作为两组球,一组是主动去吃的大球,一组是被吃的小球
-
将两组球逐一进行比较
- 被吃过就略过
- 如果比较是同一个球就略过
- 如果大小不合适就略过
- 如果不是包含关系就略过
- 如果是包含关系就认为吃到了
-
记录下每个被吃到的球
-
将所有被吃到的球删除
实现:
-
将小球看作两组,一组为大,一组为小
-
定义一个boolean数组记载哪一个球被吃到了,数组元素默认值是false表示没被吃到
-
遍历每个大球再遍历每个小球,检查大能否吃小
- 如果已经在boolean数组中标记过就忽略
- 如果两个球的引用相同就忽略
- 如果能吃到,就记录在boolean中,值为true
-
遍历boolean数组,将没有标记为吃掉的球复制到新数组中
-
删除被吃球:对新数组缩容,并且替换Ball数组
代码:
public class BallApp extends App{
Ball[]balls=new Ball[200];
public BallApp() {
for(int i=0; i<balls.length; i++) {
balls[i]=new Ball();
}
}
public void painting(Graphics2D g) {
for(int i=0; i<balls.length; i++) {
balls[i].move();
balls[i].paint(g);
}
eating();
}
public void eating() {
//一组大球,一组小球
Ball[] big=balls;
Ball[] small=balls;
boolean[] eaten=new boolean[small.length];//创建了吃掉标志 默认都是flash 表示没有吃掉
int n=0;//记录有几个球被吃掉
for(int i=0; i<big.length; i++) {//每一个大球
//如果大球已经被吃掉了,就忽略
if(eaten[i]) {
continue;
}
for(int j=0; j<small.length;j++) {
//球不能吃自己
if(i==j) {
continue;
}
//如果小球是被吃掉的就忽略
if(eaten[j]) {
continue;
}
if(big[i].eat(small[j])) {
//System.out.println("吃...");
//System.out.println(big[i].x +","+big[i].y +","+big[i].d);
//System.out.println(small[i].x +","+small[i].y +","+small[i].d);
//把小球位置设置为true
eaten[j]=true;
n++;
}
}
}
System.out.println(Arrays.toString(eaten));
System.out.println(n);
if(n==0) {
return;
}
//缩容处理
Ball[] arr=new Ball[small.length];
int index=0;
for(int i=0; i<small.length; i++) {
if(!eaten[i]) {
arr[index++]=small[i];
}
}
System.out.println(Arrays.toString(arr));
//缩容,并且替换原始数据
balls=Arrays.copyOf(arr, arr.length-n);
}
public static void main(String[] args) {
BallApp app=new BallApp();
app.start();
}
}
测试:
public class EatingTest {
public static void main(String[] args) {
/*
* 测试,全部的球相互吃的算法
*/
BallApp app=new BallApp();
System.out.println(Arrays.toString(app.balls));
System.out.println(app.balls.length);
app.eating();
System.out.println(app.balls.length);
}
}
5 完整的吃泡泡
5.1Ball
public class Ball {
double x;
double y;
int d;
int r;
int g;
int b;
Color color;
double offsetx;
double offsety;
public Ball() {
d=(int)(Math.random()*(30-2)+2);
x=Math.random()*(800-d);
y=Math.random()*(600-d);
r=(int)(Math.random()*256);
g=(int)(Math.random()*256);
b=(int)(Math.random()*256);
color=new Color(r,g,b);
offsetx=Math.random()*(6-1)*1;
offsety=Math.random()*(6-1)*1;
offsetx=Math.random()>0.5?offsetx : -offsetx;
offsety=Math.random()>0.5?offsety : -offsety;
}
public void move() {
x+=offsetx;
y+=offsety;
if(x>800-d) {
offsetx=-offsetx;
System.out.println("碰到右边缘: "+x+","+d);
x=800-d;
}else if(y>600-d) {
offsety=-offsety;
System.out.println("碰到下边缘: "+y+","+d);
y=600-d;
}else if(x<0) {
offsetx=-offsetx;
System.out.println("碰到左边缘: "+x+","+d);
x=0;
}else if(y<0) {
offsety=-offsety;
System.out.println("碰到上边缘: "+y+","+d);
y=0;
System.out.println(x+","+y);
System.out.print(offsetx+","+offsety);
}
}
public void paint(Graphics2D g) {
g.setColor(color);
g.fillOval((int)x,(int)y,d,d);
}
public boolean eat(Ball ball) {
double X=x, Y=y, D=this.d;//大球
double x=ball.x, y=ball.y, d=ball.d;//小球
//检查球的直径是否合理
if(d>D) {
return false;//直径不合理,不进行进一步比较
}
//利用勾股定理计算两个球之间的距离
double a=(X+D/2)-(x+d/2);
double b=(y+d/2)-(Y+D/2);
double c=Math.sqrt(a*a+b*b);
boolean eaten=c<D/2-d/2;
//如果发生吃了就进行两个圆的合并
if(eaten) {
//计算合并以后的圆面积
double R=D/2,r=d/2;
double area=Math.PI*R*R+Math.PI*r*r;
double rx=Math.sqrt(area/Math.PI);
this.d=(int)rx*2;//替换当前圆的直径
}
return eaten;
}
}
5.2 BallApp
public class BallApp extends App{
Ball[]balls=new Ball[200];
public BallApp() {
for(int i=0; i<balls.length; i++) {
balls[i]=new Ball();
}
}
public void painting(Graphics2D g) {
for(int i=0; i<balls.length; i++) {
balls[i].move();
balls[i].paint(g);
}
eating();
}
public void eating() {
//一组大球,一组小球
Ball[] big=balls;
Ball[] small=balls;
boolean[] eaten=new boolean[small.length];//创建了吃掉标志 默认都是flash 表示没有吃掉
int n=0;//记录有几个球被吃掉
for(int i=0; i<big.length; i++) {//每一个大球
//如果大球已经被吃掉了,就忽略
if(eaten[i]) {
continue;
}
for(int j=0; j<small.length;j++) {
//球不能吃自己
if(i==j) {
continue;
}
//如果小球是被吃掉的就忽略
if(eaten[j]) {
continue;
}
if(big[i].eat(small[j])) {
System.out.println("吃...");
System.out.println(big[i].x +","+big[i].y +","+big[i].d);
System.out.println(small[i].x +","+small[i].y +","+small[i].d);
//把小球位置设置为true
eaten[j]=true;
n++;
}
}
}
System.out.println(Arrays.toString(eaten));
System.out.println(n);
if(n==0) {
return;
}
//缩容处理
Ball[] arr=new Ball[small.length];
int index=0;
for(int i=0; i<small.length; i++) {
if(!eaten[i]) {
arr[index++]=small[i];
}
}
System.out.println(Arrays.toString(arr));
//缩容,并且替换原始数据
balls=Arrays.copyOf(arr, arr.length-n);
}
public static void main(String[] args) {
BallApp app=new BallApp();
app.start();
}
}

浙公网安备 33010602011771号