一、数组
概念:
- 存储多个数据(一组数据的容器)
- 元素:数组中数据
- 下标/索引:元素的编号,从0开始
数组的声明:
数据类型[] 数组名;
1. 数组的初始化
- 静态初始化:初始化时,数据由程序员给定,长度由系统自动分配
- 动态初始化:初始化时,长度由程序员给定,数据由系统分配默认值
- 整数类型默认:0
- 浮点类型默认:0.0
- 字符类型默认:’ ’
- 布尔类型默认:false
- 引用类型默认:null(空)
//静态初始化--通过下标设置元素
names[0] = "御坂美琴";
names[1] = "本间芽衣子";
names[2] = "小鸟游六花";
names[3] = "椎名真白";
names[4] = "一之濑千鹤";
//names[5] = "托尔"; --报错ArrayIndexOutOfBoundsException数组下标越界异常
//动态初始化1
//String[] names = new String[5];
//动态初始化2
String[] names;
names = new String[5];
初始化的应用场景:
静态初始化:一开始我们知道数据
动态初始化:一开始我们知道长度
注意:
- 数组是引用数据类型
- 数组可以存储多个数据(这个是和变量最大的不同)
- 数组一旦初始化后,长度不可以改变
2. 数组的访问
通过下标获取元素
String str = names[3];
System.out.println("通过下标获取元素:" + str);//椎名真白
获取数组的长度
int len = names.length;
System.out.println("数组长度为:" + len);//5
遍历:数组从头到尾浏览一遍
//遍历 - for循环
for (int i = 0; i < names.length; i++) {
System.out.println(names[i]);
}
//遍历 - foreach(增强for循环)
for (String s : names) {
System.out.println(s);
}
for & foreach
for循环中可以操作下标
foreach循环中不可以操作下标
3. 数组的排序
冒泡排序
口诀:
N个数字来排队
两两相比,小靠前
外层循环N-1
内层循环N-1-i
int[] array = {45, 69, 32, 28, 52, 18};
for (int i = 0; i < array.length - 1; i++) {
for (int j = 0; j < array.length - 1 - i; j++) {
if (array[j] > array[j + 1]) {
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
for (int num : array) {
System.out.println(num);
}
4. 数组的查找
1. 顺序查找
从头到尾遍历
int[] array = {45, 69, 32, 28, 52, 18};
int num = 69;
for (int i = 0; i < array.length; i++) {
if (array[i] == num) {
System.out.println("查找到数据了");
}
}
2. 二分查找
将数组一分为二,前提:必须先排序
int[] array = {45, 69, 32, 28, 52, 18};
int num = 69;
//排序 18,28,32,45,52,69
Arrays.sort(array);
int start = 0;
int end = array.length - 1;
while (start <= end) {
int mid = (start + end) / 2;
if (num < array[mid]) {
end = mid - 1;
} else if (num > array[mid]) {
start = mid + 1;
} else {
System.out.println("找到数据了");
break;
}
}
二、一维数组扩展
1. 数组的复制
方法1:
缺点:改变原数组的数据,新数组的数据也随之改变
//原数组
String[] names = {"樱岛麻衣", "椎名真白", "一之濑千鹤", "伊卡洛斯"};
//新数组
String[] newNames = names;
//改变原数组的数据
names[3] = "宫水三叶";
//遍历新数组
for (String str : newNames) {
System.out.println(str);
}
方法2:
//原数组
String[] names = {"樱岛麻衣", "椎名真白", "一之濑千鹤", "伊卡洛斯"};
//新数组
String[] newNames = new String[names.length];
//将原数组中的数据拷贝到新数组中
for (int i = 0; i < names.length; i++) {
newNames[i] = names[i];
}
//改变原数组的数据
names[3] = "小鸟游六花";
//遍历新数组
for (String str : newNames) {
System.out.println(str);
}
2. 数组的扩容
//原数组
String[] names = {"樱岛麻衣", "椎名真白", "一之濑千鹤", "伊卡洛斯"};
//新数组
String[] newNames = new String[names.length * 2];
//将原数组中的数据设置到新数组中
for (int i = 0; i < names.length; i++) {
newNames[i] = names[i];
}
//将新数组的地址赋值给原数组的引用
names = newNames;
//遍历原数组
for (String str : names) {
System.out.println(str);
}
3. 数组的删除
方法1:
缺点:数组本身就是存放数据的容器,这种方式的删除会让数组的长度越变越小
//原数组
String[] names = {"樱岛麻衣", "椎名真白", "一之濑千鹤", "伊卡洛斯"};//长度:4
//新数组
String[] newNames = new String[names.length - 1];//长度:3
//数据的迁移:要删除的数据不做迁移
int index = 0;
for (String str : names) {
if (!str.equals("伊卡洛斯")) {
newNames[index] = str;
index++;
}
}
//将新数组的地址赋值给原数组
names = newNames;
//遍历原数组
for (String str : names) {
System.out.println(str);
}
方法2:
//原数组
String[] names = {"樱岛麻衣", "椎名真白", "一之濑千鹤", "伊卡洛斯", "本间芽衣子", "小鸟游六花"};
//做数据的移动
for (int i = 3; i < names.length - 1; i++) {
names[i] = names[i + 1];
}
//把最后一个下标置为null
names[names.length - 1] = null;
//遍历原数组
for (String str : names) {
System.out.println(str);
}
4. 数组参数和返回值
需求:设计一个方法,传入int数组,返回最大值和最小值
public static void main(String[] args) {
int[] array = {45, 69, 32, 28, 52, 18};
int[] newArray = method(array);
System.out.println("最大值为:" + newArray[0]);
System.out.println("最小值为:" + newArray[1]);
}
public static int[] method(int[] array) {
int max = array[0];//假设数组的最大值是下标为0位置的数据
int min = array[0];//假设数组的最小值是下标为0位置的数据
//从下标为1的位置开始遍历数组
for (int i = 1; i < array.length; i++) {
if (max < array[i]) {
max = array[i];
}
if (min > array[i]) {
min = array[i];
}
}
return new int[]{max, min};
}
5. 可变参数
注意:可变参数本质意义上就是数组
结构:
方法名(数据类型... 变量名)//重点是这个...
案例:设计一个方法,传入n个int值,返回数据之和
public static void main(String[] args) {
//传入实参作为数组的元素
int sum = add(1, 2, 3, 4, 5, 6, 7, 8, 9);
System.out.println(sum);
}
public static int add(int... array) {
int sum = 0;
for (int num : array) {
sum += num;
}
return sum;
}
}
注意: 可变参数后面不能加其他任何参数
public static void main(String[] args) {
//传入实参作为数组的元素
method("可", "变", "参", "数");
}
//可变参数前面可以加其他参数
public static void method(String str, String... ss) {
System.out.println(str);
System.out.println(Arrays.toString(ss));
}
6. Arrays工具类
含义:Java提供的专门操作数组的工具类
工具类:该类里的所有方法都是静态的
int[] array = {45, 69, 32, 28, 52, 18};
//排序(18,28,32,45,52,69)
Arrays.sort(array);
//替换(把数组中的所有元素替换成888)
Arrays.fill(array,888);
//替换局部:从开始下标处(包含)替换到结束下标处(不包含)
Arrays.fill(array,1,4,666);
//将数组转换为字符串
String str = Arrays.toString(array);
System.out.println(str);
数组查询binarySearch()方法
如果key在数组中,则返回搜索值的索引;否则返回
-(插入点)
。
插入点是索引键将要插入数组的那一点,即第一个大于该键的元素索引。
int[] array = {45, 69, 32, 28, 52, 18};
//查找(返回值:如果key在数组中,就返回数组的下标)
int index = Arrays.binarySearch(array, 32);
System.out.println("下标为:" + index);
三、二维数组
含义:二维数组中包含了多个一维数组
数组的声明:
数据类型[][] 数组名;
数组的初始化:
- 静态初始化:数据由程序员指定,长度由系统自动分配
- 动态初始化:长度由程序员指定,数据由系统赋默认值
- 整数类型:0
- 浮点类型:0.0
- 字符类型:’ ’
- 布尔类型:false
- 引用类型:null
静态初始化
//静态初始化1
String[][] names = {{"御坂美琴","本间芽衣子","小鸟游六花"},{"椎名真白","一之濑千鹤","伊卡洛斯"}};
//静态初始化2
String[][] names;
names = new String[][]{{"御坂美琴","本间芽衣子","小鸟游六花"},{"椎名真白","一之濑千鹤","伊卡洛斯"}};
//静态初始化3
String[][] names = new String[][]{{"御坂美琴","本间芽衣子","小鸟游六花"},{"椎名真白","一之濑千鹤","伊卡洛斯"}};
动态初始化
String[][] names = new String[2][3];//2-二个一维数组,3-每个一维数组都有三个元素
通过下标设置元素
names[0][0] = "本间芽衣子";
names[0][1] = "小鸟游六花";
names[0][2] = "一之濑千鹤";
names[1][0] = "椎名真白";
names[1][1] = "伊卡洛斯";
names[1][2] = "爱蜜莉雅";
通过下标获取元素
String str = names[0][1];
System.out.println("通关下标获取元素:" + str);
获取长度
System.out.println("获取二维数组中一维数组的个数:" + names.length);//2
System.out.println("获取二维数组中第一个一维数组元素的个数:" + names[0].length);//3
System.out.println("获取二维数组中第二个一维数组元素的个数:" + names[1].length);//3
遍历
遍历思路:循环取出一维数组,再循环取出一维数组的元素
//遍历 -- for
for (int i = 0; i < names.length; i++) {
for (int j = 0; j < names[i].length; j++) {
System.out.println(names[i][j]);
}
}
//遍历 -- foreach
for (String[] ss : names) {
for (String s : ss) {
System.out.println(s);
}
}
需求:利用二维数组的动态初始化,实现第一个一维数组元素个数为3,第二个一维数组的元素个数为4
String[][] names = new String[2][];
names[0] = new String[3];
names[1] = new String[4];
案例:五子棋
import java.util.Scanner;
public class GoBang {
public static void main(String[] args) {
int len = 20;//棋盘长度
String[][] goBang = new String[len][len];//棋盘容器
//棋盘符号
String add = "╋";
String black = "■";
String white = "○";
String[] nums = {"⒈", "⒉", "⒊", "⒋", "⒌", "⒍", "⒎", "⒏", "⒐", "⒑", "⒒", "⒓", "⒔", "⒕", "⒖", "⒗", "⒘", "⒙", "⒚", "⒛"};
//初始化棋盘数据
for (int i = 0; i < goBang.length; i++) {
for (int j = 0; j < goBang[i].length; j++) {
if (j == len - 1) {//每一行的最后一列
goBang[i][j] = nums[i];
} else if (i == len - 1) {//最后一行
goBang[i][j] = nums[j];
} else {
goBang[i][j] = add;
}
}
}
//打印棋盘
for (String[] strings : goBang) {
for (String string : strings) {
System.out.print(string);
}
System.out.println();
}
Scanner scan = new Scanner(System.in);
boolean flag = true;//true-黑子 false-白子
while (true) {
System.out.println("请" + ((flag) ? "黑" : "白") + "子输入坐标:");
int x = scan.nextInt() - 1;
int y = scan.nextInt() - 1;
//判断坐标是否超出棋盘范围
if (x < 0 || x > len - 2 || y < 0 || y > len - 2) {
System.out.println("坐标超出棋盘范围,请重新输入...");
continue;
}
//判断坐标上是否有棋子
if (!goBang[x][y].equals(add)) {
System.out.println("坐标有棋子,请重新输入...");
continue;
}
//落子
goBang[x][y] = (flag) ? black : white;
//置反
flag = !flag;
//打印棋盘
for (String[] strings : goBang) {
for (String string : strings) {
System.out.print(string);
}
System.out.println();
}
}
}
}