数组
一、数组
1.1数组概念
数组是存储同一种数据类型多个元素的集合,也可以看成是一个容器。
数组既可以存储基本数据类型,也可以存储引用数据类型。
数组属于引用类型,可以理解为对象(Object),数组中的每个元素相当于该对象的成员变量。
数组一旦初始化,长度不可变。
1.2数组特点
- 数组中保存的数据必须是相同的数据类型
- 数组是定长的(数组一旦定义,那么长度是不可改变的)数组长度:
数组名.length
二、数组的创建
2.1动态初始化
- 语法1:
数据类型 [] 数组名 = new 数据类型 [长度] ;
- 语法2:
数据类型 数组名[] = new 数据类型 [长度];
public class Demo {
public static void main(String[] args) {
//数据类型 [ ] 数组名 = new 数据类型 [ 长度] ;
//创建int类型的数组,长度为5
int[] arr1 = new int[5];
//数据类型 数组名[] = new 数据类型 [长度];
int arr2[] = new int[5];
}
}
2.2静态初始化
- 语法1:
数据类型 [] 数组名 = {数据1,数据2...};
- 语法2:
数据类型 数组名[] = {数据1,数据2...};
- 语法3:
数据类型[] 数组名=new 数据类型[] {数据1,数据2...};
- 注意:
- 数组静态初始化必须在一起不分开
- 数组是引用数据类型
- 数组直接输出是内存地址 基本数据类型在栈中 引用数据类型堆中
public class Demo {
public static void main(String[] args) {
//数据类型 [] 数组名 = {数据1,数据2...};
String[] arr1 = {"aaa","bbb","ccc"};
//数据类型 数组名[] = {数据1,数据2...};
String arr2[] = {"aaa","bbb","ccc"};
//数据类型[] 数组名=new 数据类型[] {数据1,数据2...};
String[] arr3 = new String[]{"aaa","bbb","ccc"};
}
}
2.3数组使用细节
-
数组中每一个数据都称之为元素
-
数组中每一个元素都有对应的下标
-
数组中的每个元素都是有编号的,并且是从0开始。最大编号是:
数组的长度-1
。 -
数组名和编号的配合就可以获取数组中的指定编号的元素。这个编号的专业叫法:
索引(下标)
。 -
通过数组名访问数据的格式是:
数组名[下标]
。 -
数组长度其实就是数组中元素的个数,每个数组都有一个属性
length
指明它的长度 -
数组索引越界异常
ArrayIndexOutOfBoundsException
- 访问到了数组中的不存在的索引时发生
-
空指针异常
NullPointerException
- 数组引用没有指向实体,却在操作实体中的元素时
三、数组的遍历
-
遍历:获取、保存数组中的每一个元素(循环实现)
public class Demo { public static void main(String[] args) { Scanner sc = new Scanner(System.in); //创建长度为10的int类型数组 int[] arr = new int[10]; //遍历输入数组中的值 for (int i = 0; i < arr.length; i++) { System.out.println("请输入第"+i+1+"个数字:"); arr[i]=sc.nextInt(); } System.out.println("+++++++++++++++++++++++++++++++++++++++"); //遍历出数组中的元素 for (int i = 0; i < arr.length; i++) { //arr[i]表示数组中每一个元素 System.out.println(arr[i]); } } }
四、数组的默认值
- 数组在创建时没有赋值是有默认值的
- 存放基本数据类型数据的数组每个元素的初始值
int
:0byte
:0short
:0long
:0float
:0.0double
:0.0char
:'\u0000','',0
boolean
:false
- 存放引用数据类型数据的数组每个元素的初始值:
null
- 存放基本数据类型数据的数组每个元素的初始值
- null是一种特殊的值,表示当前对象在内存中没有指向任何地址
" "
表示空字符串在内存当中是有地址的
- 数组在创建时没有赋值是有默认值的
五、数组扩容
6.1实现数组扩容和缩容
- 扩容和缩容
- 步骤一:定义一个数组,新数组长度要比原数组增加或减小
- 步骤二:将原数组的元素拷贝到新数组中
- 步骤三:将原来数组的变量指向新数组
//数组扩容
public class Demo {
public static void main(String[] args) {
//定义数组 数组长度要比原数组长(短)
int[] oldArr={1,2,3};
//创建新数组 长度为原数组长度+1
int[] newArr = new int[oldArr.length+1];
//将原来数组的元素拷贝到新数组
for (int i = 0; i < oldArr.length; i++) {
newArr[i]=oldArr[i];
}
//将数组指向新数组的地址
oldArr=newArr;
for (int i = 0; i < oldArr.length; i++) {
System.out.println(oldArr[i]);
}
}
}
//数组缩容
public class Demo {
public static void main(String[] args) {
//定义原数组
int[] oldArr = {1,2,3};
//定义新数组
int[] newArr =new int[oldArr.length-1];
//数组拷贝
for (int i = 0; i < newArr.length; i++) {
newArr[i] = oldArr[i];
}
//将原数组地址指向新地址
oldArr=newArr;
for (int i = 0; i < oldArr.length; i++) {
System.out.println(oldArr[i]);
}
}
}
6.2数组拷贝
数组拷贝有三种方式:
- 循环将原数组中所有元素逐一复制到新数组;
System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
import java.util.Arrays;
public class Demo {
public static void main(String[] args) {
int[] arr1 = {1,2,3};
int[] arr2 = new int[arr1.length+5];
/*
* 参数1:原数组
* 参数2:原数组的起始位置
* 参数3:目标数组
* 参数4:目标数组的起始位置
* 参数5:数组拷贝的长度
* */
System.arraycopy(arr1,0,arr2,0,arr1.length);
//将数组中的值转换成字符串输出
System.out.println(Arrays.toString(arr2));
}
}
Arrays.copyOf(原数组,新长度);
import java.util.Arrays;
public class Demo {
public static void main(String[] args) {
int[] arr1 = {1,2,3};
//使用Arrays提供数组拷贝方法
arr1=Arrays.copyOf(arr1,arr1.length+1);
//打印数组
System.out.println(Arrays.toString(arr1));
}
}
七、数组的排序
7.1冒泡排序(对数组顺序进行排序)
- 冒泡排序的思想:
- 将相邻的两个元素进行比较如果前面一个元素比后面一个元素大就交换位置(在一轮比较当中)知道比较完整的数组
- 在这一轮可以将最大的元素放到最后
- 以上操作完成数组的长度-1
- 将相邻的两个元素进行比较如果前面一个元素比后面一个元素大就交换位置(在一轮比较当中)知道比较完整的数组
import java.util.Arrays;
public class Demo {
public static void main(String[] args) {
//int[] arr = {3,5,7,9,5,1,2,6,4,8};
//int[] arr = {1,2,3,4,5,6,7,8,9};
int[] arr = {9,8,7,6,5,4,3,2,1,0};
//方法调用
sort(arr);
}
//冒泡排序的基本实现
public static void sort(int[] arr){
for(int i = 0; i < arr.length-1; i++) {//轮数
boolean flag = true; //假设数组已经排好顺序
for(int j = 0; j < arr.length - 1 - i; j++) {
if(arr[j] > arr[j+1]) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
flag = false;
}
}
if(flag) {
break;
} else {
flag = true; //重置标志位
}
}
System.out.println(Arrays.toString(arr));
}
}
7.2选择排序
- 选择排序思想
- 将当前位置上的元素与后面每一个元素进行比较,如果有比当前位置小的元素就先记录下来,等所有元素比较完成之后,进行交换。这个过程可以将最小的值交换到当前位置
- 以上操作可以将最小选择到指定位置循环操作进行每一个位置挑选
import java.util.Arrays;
public class Demo {
public static void main(String[] args) {
//int[] arr = {3,5,7,9,5,1,2,6,4,8};
//int[] arr = {1,2,3,4,5,6,7,8,9};
int[] arr = {9,8,7,6,5,4,3,2,1,0};
sort(arr);
}
//选择排序的基本实现
public static void sort(int[] arr){
for(int i = 0; i < arr.length - 1; i++) {//i表示被选定元素的下标
for(int j = i+1; j < arr.length; j++) {//j表示和选定的元素进行比较的元素----"其后的元素"
//比较
if(arr[i] > arr[j]) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
7.3Arrays工具类排序方法
import java.util.Arrays;
public class Demo {
public static void main(String[] args) {
int[] arr = {1,5,9,3,5,7,8,4,6,2};
//Arrays工具类提供sort方法排序
Arrays.sort(arr);
//将数组转换成字符串输出
System.out.println(Arrays.toString(arr));
}
}
八、二分查找法
- 二分查找法(折半查找法)
- 前提:数组元素是有序的
- 思路:
- 首先找到这个数组的中间数,与找到的中间元素比较,如果相等就代表找到了
- 如果传入的数据比中间数大,那么就表示想找的数再元素中间值的右边,所以最小值的下标等于中间值的下标+1
- 如果传入的数据比中间数小,那么就表示想找的数再元素中间值的做边,所以最小值的下标等于中间值的下标-1
public static int binarySearch(int[] arr,int num){
//获取最大值 最小值
int min=0;
int max=arr.length-1;
while (min<=max){
//获取中间值
int middle = (min+max)/2;
//将查找的数与中间值比较
if (num>arr[middle]){
min=middle+1;
}else if (num<arr[middle]){
max=middle-1;
}else{
return middle;
}
}
return -1;
}
}
九、二维数组
9.1什么是二维数组
- 数组中包含数组
- 本质是一维数组
9.2二维数组定义及初始化
public class Demo {
public static void main(String[] args) {
/*
4行3列
该数组中包含4个一维数组,每个一维数组包含3个元素
*/
int[][] arr = new int[4][3];//动态初始化
//System.out.println(arr.length);
for(int i = 0; i < arr.length; i++) { //行
for(int j = 0; j < arr[i].length; j++) {
System.out.println(arr[i][j]);
}
}
/*
二维数组每一行的长度可以不相同
*/
int[][] arr1 = new int[3][];//动态初始化
arr1[0] = new int[10];
arr1[1] = new int[9];
arr1[2] = new int[11];
//int[] arr = new int[]{...};
//int[][] arr2 = new int[][]{{1, 2, 3}, {4, 5}, {0, 0 ,0}};
int[][] arr2 = {{1, 2, 3}, {4, 5}, {0, 0 ,0}};
for(int i = 0; i < arr2.length; i++) {
for(int j = 0; j < arr2[i].length; j++) {
System.out.print(arr2[i][j] + "\t");
}
System.out.println();
}
}
}
9.3杨辉三角
public class Demo {
public static void main(String[] args) {
//创建二维数组
int[][] arr = new int[10][];
for(int i = 0; i < arr.length; i++) {
arr[i] = new int[i + 1];
for(int j = 0; j < arr[i].length; j++) {
if(j == 0 || j == arr[i].length - 1) {
arr[i][j] = 1;
} else {
arr[i][j] = arr[i - 1][j - 1] + arr[i - 1][j];
}
}
}
for(int i = 0; i < arr.length; i++) {
for(int j = 0; j < arr[i].length; j++) {
System.out.print(arr[i][j] + "\t");
}
System.out.println();
}
}
}
十、可变参数
-
概念:可接收多个同类型实参,个数不限,使用方式与数组相同。
-
语法:
数据类型... 参数名
-
特点:
- 带有可变参数方法调用的时候实参可以是0个或者多个
- 必须定义在形参列表的最后,且只能有一个
- 可变参数可以当作数组来使用,也可以将数组变为参数使用
10.1可变参数方法的定义及调用
public class Demo {
public static void printArray(int... args) {
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
public static void main(String[] args) {
//int[] arr = {2, 3, 5, 0, 1};
//printArray(arr);
printArray(1, 2, 3);
}
}
十一、值传递和引用传递
- 值传递:传递的是值,原来的值不会改变,所有的基本数据类型+String都是数用值传递
- 引用传递:传递的是地址,所以会对原来的内容有影响,所有的引用数据类型都属于引用传递