第二章 不要小瞧数组
2-1 使用Java中的数组
2-2 二次封装属于我们自己的数组
2-3 向数组中添加元素
2-4 数组中查询元素和修改元素
2-5 包含,搜索和删除
2-1 使用Java中的数组
数组概念:把数据码成一排进行存放
数组中存在一个很重要的概念:索引
- 由于数组中每一个元素都是一个一个挨着排队存放的,那么就可以给数组中的每个元素一个编号。n个元素的索引:第一个元素的索引是0,最后一个元素的索引是n-1。有了索引,就可以快速地直接访问第i个元素是谁(如图所示)
Java中的数组如下:
public class Main {
public static void main(String[] args) {
// write your code here
int[] arr = new int[10];
for (int i = 0; i < arr.length; i++)
arr[i] = i;
int[] scores = new int[]{100, 99, 66};
//方法一
for (int i = 0; i < scores.length; i++)
System.out.println(scores[i]);
//可以修改数组中的变量
scores[0]=98;
//方法二
for (int ss:scores)
System.out.println(ss);
}
}
2-2 二次封装属于我们自己的数组
数组最大的优点:快速查询。数组最好应用于“索引有语意”的情况,但并非所有有语意的索引都适用于数组。
举个栗子:设计一个数组,不同的数组存放不同的人的工资情况,索引到不同的人可以使用身份证号(ex. 身份证号 110103198512166666)
- 因为数字太大了,数组需要开辟这样的一个大空间是不值当的,甚至是不可能。就算开辟出这样一个空间,对于很多空间都是浪费的。因为我可能只想要一个小组内10个人的个人情况,却要开辟出这样大的空间。
数组也可以处理“索引没有语意”的情况,在这一章,主要处理“索引没有语意”的情况数组的使用
方法:基于Java的数组,二次封装属于我们自己的数组类(动态数组)
capacity: 数组空间最多可以装多少个元素
size: 数组中实际有多少个元素
初始化数组时一个元素都没有,此时size应该等于0,相当于指向了第一个没有元素的索引data[0]
public class Array {
// 类的成员变量都是私有的(private)
private int[] data;
private int size;
// 构造函数,传入数组的容量capacity构造Array
public Array(int capacity){
data = new int[capacity];
size = 0;
}
// 无参数的构造函数,默认数组的容量capacity=10
public Array(){
this(10);
}
// 获取数组中的元素个数
public int getSize(){
return size;
}
// 获取数组的容量
public int getCapacity(){
return data.length;
}
// 返回数组是否为空
public boolean isEmpty(){
return size == 0;
}
}
2-3 向数组添加元素
(1)向数组末尾添加元素(size位置的元素实际上就是数组末尾的元素)
// 向所有元素后添加一个新元素e
public void addLast(int e){
if(size == data.length)
throw new IllegalArgumentException("AddLast failed. Array is full.")
data[size] = e;
size ++;
}
(2)向指定位置添加元素
在数组元素中间添加元素时,需要从后向前依次挪一个位置,在先前的副本元素保存好之后,随后挪移的元素会覆盖之前的元素 (换句话说:移动位置并不能使该位置为空,而是有了“副本”之后,原数据可以被覆盖)
- 检查数组的元素个数size是否超出容量,不合法抛出异常
- 检查"插入元素的位置index"这个变量是否合法,不合法抛出异常
// 在第index个位置插入一个新元素e
public void add(int index, int e){
if (size == data.length)
throw new IllegalArgumentException("Add failed. Array is full.");
if (index < 0 || index > size)
throw new IllegalArgumentException("Add failed. Required index >= 0 and index <= size ");
for (int i = size - 1; i >= index; i --)
data[i+1] = data[i];
data[index] = e;
size ++;
}
(3)在所有元素前添加一个新元素
这里要注意的是,调用了(2)的add方法,从而可以简化(1)&(2)
// 在所有元素前添加一个新元素e
public void addFirst(int e){
add(0,e);
}
// 向所有元素后添加一个新元素e
public void addLast(int e){
add(size, e);
}
2-4 数组中查询元素和修改元素
(1)在“子类”中重写默认父类的方法
toString方法:返回对象的字符串表示
该方法重写/覆盖(@Override)了父类的toString方法(public String toString),同时在代码编写错误时,编译器会提示方法名称错误
@Override //覆盖父类的方法
public String toString(){
StringBuilder res = new StringBuilder();
res.append(String.format("Array:size = %d, capacity = %d\n", size, data.length));
res.append('[');
for (int i = 0; i < size; i++){
res.append(data[i]);
if (i != size - 1)
res.append(", ");
}
res.append(']');
return res.toString();
}
字符串最终输出形式如下:简单明了的信息表达方式(建议所有子类都重写toString方法)
(2)使用我们自己的Array对象测试一下
public class Main {
public static void main(String[] args) {
Array arr = new Array(20);
for (int i = 0; i < 10; i ++)
arr.addLast(i);
System.out.println(arr);
arr.add(1,100);
System.out.println(arr);
arr.addFirst(-1);
System.out.println(arr);
}
}
输出结果如下:
(3)如何获取某个索引位置的元素
在get方法中只传入index的值,返回data[index],这样做相当于对data静态数组进行了隐藏。
- 这样只能获取index位置的元素,而不能获取整个静态数组data。好处是可以在中间加入对index是否合法的判断、也解决了未使用空间如何处理的问题。该方法使得用户永远无法去查询那些没有使用的空间的信息 (capacity>=size),从而保护数据安全)
// 获取index索引位置的元素
int get(int index){
if (index < 0 || index >= size)
throw new IllegalArgumentException("Get failed. Index is illegal. Required index >= 0 and index < size ");
return data[index];
}
(4)如何修改某个索引位置的元素
使用set方法实现对数据的更新,同时也要检查index是否合法
// 修改index索引位置的元素为e
void set(int index, int e){
if (index < 0 || index >= size)
throw new IllegalArgumentException("Get failed. Index is illegal. Required index >= 0 and index < size ");
data[index] = e;
}
2-5 数组中包含、搜索和删除
(1)查找数组中是否有元素e,并查询其所在的索引
// 查找数组中是否有元素e
public boolean contains(int e){
for (int i = 0; i < size; i ++){
if (data[i] == e)
return true;
}
return false;
}
// 查找数组中元素e所在的索引,如果不存在元素e,则返回-1
public int find(int e){
for (int i = 0; i < size; i ++){
if (data[i] == e)
return i;
}
return -1;
}
(2)从数组中删除元素
- 从数组中删除index位置的元素
// 从数组中删除index位置的元素,返回删除的元素
public int remove(int index){
if (index < 0 || index >= size)
throw new IllegalArgumentException("Get failed. Index is illegal. Required index >= 0 and index < size ");
int ret = data[index];
for (int i = index + 1; i < size; i ++)
data[i-1] = data[i];
size --;
return ret;
}
- 从数组中删除第一个元素
// 从数组中删除第一个元素,返回删除的元素
public int removeFirst(){
return remove(0);
}
- 从数组中删除最后一个元素
// 从数组中删除最后一个元素,返回删除的元素
public int removeLast(){
return remove(size-1);
}
- 从数组中删除元素e
// 从数组中删除元素e
public void removeElement(int e){
int index = find(e);
if (index != -1)
remove(index);
}
使用Array对象测试一下,测试代码及输出结果如下:
// Original array: [-1, 0, 100, 1, 2, 3, 4, 5, 6, 7, 8, 9]
arr.remove(2);
System.out.println(arr);
//[-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
arr.removeElement(4);
System.out.println(arr);
//[-1, 0, 1, 2, 3, 5, 6, 7, 8, 9]
arr.removeFirst();
System.out.println(arr);
//[0, 1, 2, 3, 5, 6, 7, 8, 9]
arr.removeLast();
System.out.println(arr);
//[0, 1, 2, 3, 5, 6, 7, 8]