目录
- 什么是数组
- 数组的定义和内存分配
- 数组的赋值和访问
- 数组的注意事项
- 数组的内存图解
- 数组的插入
- 数组的删除
- 数组的扩容
- 数组的反转
首先
什么是数组
数组是一组地址连续、长度固定的具有相同类型的数据的集合,通过数组下标我们可以指定数字中的每一个元素
数组的定义和内存分配
在Java中通过(类型名[] 数组名)或(类型名 数组名[])申明一个数组,其中(类型名[] 数组名)方式声明数组是Java特有也是推荐使用的
数组是一个特殊的对象,所以在使用前需要在内存中开辟一块内存空间用来存放数据,否则会抛出空指针异常,可以通过(new)关键字给数组分配内存,也可以使用通过在静态初始化(见下)时隐式的给数组分配与初始化元素个数相同的数组空间
定义了一个数组后可以通过(数组名[下标])的方式访问数组中的数据,通过(数组名[下标]=数据)为数组赋值
数组的赋值和访问
数组的赋值有两种:静态初始化、动态初始化
- 静态初始化:通过(类型[] 数组名={元素,元素...})或(类型[] 数组名=[]{元素,元素...})的方式为数组初始化,数组将自动分配一个与元素个数相同的内存空间
- 动态初始化:通过(类型[] 数组名=new 类型[大小])为数组分配内存,通过(数组名[下标]=数据)为数组初始化赋值
数组的注意事项
- 数组的类型可以是基本数据类型和引用类型
- 数组的长度不可变
- 数组的属性(数组名.length)获取的是数组的容量,而不是数组中存储元素的个数
- 数组的下标从0开始,最后一个元素的下标是(length-1)
public static void main(String[] args) {
int[] arr1={1,2,3};//定义一个int类型数组arr1,静态初始化数组,其数组长度为3
int[] arr2=new int[3];//定义一个长度为3的int类型数组arr2 int类型的数组其元素默认值是0
int[] arr3=new int[]{4,5,6};//定义一个int类型数组arr2,并静态初始化数组,其数组长度为3
//(数组名.lenth)获取数组的容量大小
System.out.println("arr1的长度为 : "+arr1.length+" - ["+arr1[0]+", "+arr1[1]+", "+arr1[2]+"]");
System.out.println("arr1的长度为 : "+arr2.length+" - ["+arr2[0]+", "+arr2[1]+", "+arr2[2]+"]");
System.out.println("arr1的长度为 : "+arr3.length+" - ["+arr3[0]+", "+arr3[1]+", "+arr3[2]+"]");
}
数组的内存图解
数组的遍历
我们常使用for循环或foreach遍历数组:见代码
1 public static void main(String[] args) {
2
3 int[] arr={1,2,3};
4 // 使用for循环遍历数组
5 for(int i=0;i<arr.length;i++){
6 System.out.print(arr[i]+", ");
7 }
8 System.out.println("\n-----快乐的分割线-----");
9 // 使用foreach遍历数组
10 /*
11 * foreach的用法
12 * for(数组类型 变量名 : 数组名){
13 * 通过 变量名 访问数组中的每个元素
14 * }
15 */
16 for(int i : arr){
17 System.out.print(i+", ");
18 }
19 }
好了,经过了对数组的简单了解后,让我们看看对数组的基本操作
插入
我们知道,通过(数组名[下标]=数据)的方式能很容易的给数组的任一位置赋值,但是如果原位置本含有数据,此时就会将原有数据覆盖,也就造成了数据丢失
所以我们可以将插入位置及之后的所有实际使用元素都向后移动一位,这样插入位置就空出来(当然也需要有足够的剩余空间,不然也是不能插入的),我们就可以插入需要的数据啦。那么怎么将插入位置及之后的实际使用的元素都后移呢,只要我们从(实际存储的最后一个元素位置+1)开始,从后往前遍历数组,将数组的前一个值赋给后一个位置,直到插入位置,这样插入位置就空出来了
当然我们还有一个小问题,因为之前说过length属性只能获得数组的容量大小,而不是实际使用的空间大小,但是在插入过程中我们需要从(实际存储的最后一个元素位置+1)进行操作,也就是我们需要获得数组的实际使用空间,怎么办呢?很容易,只要定义一个变量用来记录数组中的元素个数,当插入元素时(个数+1),当删除元素时(个数-1)就可以了
为了更清楚的理解插入操作,先上图
上代码:
1 public class ArrayOperate {
2
3 /** 给数组一个容量 此处给个5*/
4 private int capacity = 5;
5 /** 定义一个数组 数组长度为capacity给定 5*/
6 private int[] arr = new int[capacity];
7 /** 用来存储数组的实际使用空间 */
8 private int count;
9
10 /**
11 * 向数组中index下标处插入元素
12 */
13 public boolean insert(int index,int inner){
14 //---------------------【在index下标处插入元素 - 关键代码】
15 if(this.count>=this.capacity){
16 // 当实际元素个数等于数组容量时 数组已满 不能插入
17 System.err.println("数组已满");
18 return false;
19 }
20 if(index<0||index>count){
21 // 当插入位置不在(0和count)之间时 不能插入数据
22 System.err.println("请在 0-"+count+"之间插入数据");
23 return false;
24 }
25
26 for(int i=count;i>index;i--){
27 this.arr[i]=this.arr[i-1];// 数组元素依次向后移动
28 }
29 this.arr[index]=inner;//给数组index下标处赋值插入元素
30 count++;//插入数据后 实际大小需要+1
31 return true;
32 }
33
34 /** 在数组的后面添加元素 */
35 public boolean append(int inner){
36 /*
37 * 在数组的后添加元素
38 * 我们可以这样写:
39 * if(this.count>=arr.length){
40 * return false;//先判断数组是否已满 如果满了就不允许插入元素了
41 * }
42 * if(index<0||index>count){
43 * return false;
44 * }
45 * arr[count]=inner;//为数组赋值【因为数组的下标是从0开始的,所以数组的实际添加的最后一个位置是count-1,所以如果需要在后面添加元素的话arr[count]就可以了】
46 * count++;
47 * return true;
48 */
49
50 // 但是因为在之前实现了在数组index位置插入元素的方法 我们只需要调用该方法就可以了
51 // 在数组count位置插入元素
52 return insert(count,inner);
53 }
54
55 public static void main(String[] args) {
56
57 // 测试
58 ArrayOperate arrs=new ArrayOperate();
59 // 为数组初始化元素
60 arrs.append(12);
61 arrs.append(10);
62 arrs.append(5);
63 arrs.append(20);
64 System.out.println(Arrays.toString(arrs.arr));// 打印初始化的数组元素
65 // 在数组的第二位置插入16
66 arrs.insert(1, 16);
67 System.out.println(Arrays.toString(arrs.arr));// 打印插入后的数组元素
68
69 }
70
71 }
删除
既然有插入操作自然有删除,与插入相似,我们只需要将移动数据的部分反过来就可以了
上图
上代码
1 public boolean delete(int index){
2
3 // 判断数组是否为空了 如果为空,则不能再删除元素
4 if(count==0){
5 System.err.println("数组以空");
6 return false;
7 }
8 // 判断输入的下标是否超过指定范围 超过则不能再删除数据
9 if(index<0||index>=count){
10 System.out.println("请在 0-"+(count-1)+"之间删除数据");
11 return false;
12 }
13 // 从index开始,将后一个元素赋值给前面,知道到最后一个实际元素
14 for(int i=index;i<count-1;i++){//当最后一个元素时 应该是 arr[length-2]=arr[length-1]; 所以应该(i<length-1)
15 this.arr[i]=this.arr[i+1];
16 }
17 // 给最后一个元素补0
18 // 并将元素使用长度-1
19 this.arr[--count]=0;
20
21 return true;
22 }
23
24 public boolean delete(){
25 /*
26 * 同样的 我们可以调用之间写的delete(index)方法删除最后一个元素
27 * 也可以这样写
28 * if(count<=0){
29 * return false;
30 * }
31 * if(index<0||index>=count){
32 * return false;
33 * }
34 * arr[--count]=0;
35 * return true;
36 */
37 return this.delete(count-1);
38 }
1 // 测试 -- 删除数组上的第二个元素
2 arrs.delete(1);
3 System.out.println(Arrays.toString(arrs.arr));
扩容
之前我们强调过,数组长度是固定的,那么我么怎么对数组进行扩容呢?其实只要重新创建一个数组,其长度比原有数组长度大n,并将原数组中的内容复制到新数组中,然后将新数组的地址引用赋给数组变量就能完成对原数组的扩容(不过因为每次都需要新创建一个数组并复制原数组的值,所以其性能会比较低)
看一个图
理解了这个,写代码就很容易了
1 /** 给数组扩充addLength个长度 */
2 public boolean exCapacity(int addLength){
3 if(addLength<0){
4 // 如果输入的长度小于0,则禁止扩容 因为参数是负数 其新创建的数组的长度比原数组要小,在下面的复制操作中会下标越界
5 System.err.println("请输入大于0的整数");
6 return false;
7 }
8 // 创建一个临时数组 其长度为本数组长度+扩充长度
9 int[] tp=new int[this.arr.length+addLength];
10 for (int i = 0; i < this.arr.length; i++) {
11 tp[i]=this.arr[i];// 将原数组内容复制到新数组中
12 }
13 this.arr=tp;// 将新数组的地址引用赋给数组变量
14 this.capacity=this.arr.length;// 扩容后将数组的长度赋值给capacity
15 return true;
16 }
反转
在题目中我们经常会遇到将一个数组反转,那么我们先分析一个例子,[1,2,3]的反转数组为[3,2,1],[1,2,2,1]的反转数组为[1,2,2,1],此时看来,将[1,2,3]的1,3交换就变成了[3,2,1],将[1,2,2,1]的1和1交换,2和2交换同样变成了反转数组;将反转一个数组其实只需要在数组的中心位置将两边的对称位置的元素进行交换就可以了
看图
代码
1 /** 反转数组 */
2 public void reverse(){
3 // 当为count时 只对实际存储的元素进行反转
4 // 当将count转换为arr.length时 会反转整个数组
5 for(int i=0;i<count/2;i++){
6 // 交换对称的两个元素
7 int a=arr[i];
8 arr[i]=arr[count-1-i];
9 arr[count-1-i]=a;
10 }
11 }
最后附上源码
今天先讲到这里,第一次写博客ヾ ^_^♪如果有什么不对的, 欢迎大家指正,谢谢ლ(╹◡╹ლ)