数组是有限个相同类型的变量所组成的有序集合,数组中的每一个变量被称为元素。数组是最简单、最常用的数据结构。以整型数组为例,数组的存储形式为:

数组中每一个元素都有自己的下标,这个下标从 0 开始,一直到数组长度 - 1 结束。数组的另外一个特点就是在内存中顺序存储,所以可以很好地实现逻辑上的顺序表。那顺序存储是个什么样子呢?我们知道,内存是由一个个连续的内存单元组成的,每一个内存单元都有自己的地址。在这些内存单元中,有些被其他数据占用了,有些是空闲的。数组中的每一个元素都存储在小小的单元中,并且元素之间紧密排列,既不能打乱元素的存储顺序,也不能跳过每个存储单元存储。

如上图所示,连续的 8 个红色的单元我们用来存储数组,绿色的单元表示空闲的单元,数组在存储时必须是连续的,不能在内存中随意去占领空闲的单元。
数组的基本操作:
1.读取元素:对于数组来说,读取元素是最简单的操作。由于数组在内存中顺序存储,所以只需要给出一个数组的下标,就可以读取到对应的数组元素。假设有一个名称为 array 的数组,我们需要读取下标为 3 的元素,就可以写作 array[3]。需要注意的是,输入的下标必须在数组的长度范围之内,否则会出现数组越界的情况。像这种根据下标读取元素的方式叫作随机读取。时间复杂度为 。
2.更新元素:要把数组中的某一元素的值替换为另一个新值,也是常见的数组操作。直接利用下标把新值赋值给该元素即可。时间复杂度为 。
3.插入元素:由于需要考虑到数组的实际数量有可能小于数组的长度,所以插入数组元素存在三种情况,即尾部插入、中间插入和超范围插入。
尾部插入是最简单的情况,即直接把插入的元素放在数组尾部的空闲位置,等同于更新操作;中间插入的操作稍微复杂一点。由于数组中每一个元素都有其固定的下标,所以不得不首先把插入位置及后面的元素向后移动,为要插入的元素腾出地方,然后再把要插入的元素放到对应的数组位置上。那么超范围插入又是一种什么情况呢?假设不断地往数组中插入新元素,直到元素数量超过数组的最大长度时,便引出了数组的超范围插入的操作。也就是说,如果有一个长度为 6 的数组,现在已经装满了元素,这是如果还想插入一个元素的话就属于超范围插入。这时就涉及到数组的扩容,但是数组的长度在数组创建时就已经确定了,不能随意扩容或缩短。此时我们可以创建一个新的数组,长度是旧数组的两倍,再把旧数组中的元素统统复制到新数组中,这样就实现了数组的扩容。插入元素的时间复杂度为 ,因为涉及到数组元素的移动。
4.删除元素:数组的删除操作和插入过程相反,如果删除的元素位于数组中间,其后的元素都需要向前移动一位。时间复杂度是 。
相关的代码实现如下:
public class ArrayTest {
// 打印数组
public static void display(int[] array) {
System.out.print("数组中元素为:");
for (int i = 0; i < array.length - 1; i++) {
if (array[i] != 0) {
System.out.print(array[i] + "-->");
}
}
System.out.println(array[array.length - 1]);
}
/**
* @param array 数组
* @param index 下标,默认下标有效,所以不做对下标的额外处理
* 读取数组元素
*/
public static void readElement(int[] array, int index) {
// 默认输入的 index 是有效的,所以不做额外的处理
System.out.println("数组中下标为" + index + "的元素为:" + array[index]);
}
/**
* @param array 数组
* @param index 要更新元素的下标,默认有效
* @param element 要更新的新值
* 更新数组元素
*/
public static void updateElement(int[] array, int index, int element) {
System.out.println("更新下标为" + index + "的元素为:" + element);
array[index] = element;
}
/**
* @param array 数组
* @param index 插入元素的位置
* @param element 插入元素
* 往数组中插入元素
*/
public static int[] insertElement(int[] array, int index, int element) {
int size = array.length;
// 判断插入位置是否合法
if (index < 0 || index >= size - 1) {
System.out.println("插入位置非法!");
return array;
}
// 如果数组实际元素达到数组容量上限,则扩容,测试时该条件恒为 true
int[] newArray = new int[array.length * 2];
if (size >= array.length) {
// 复制 array 到 newArray 中
System.arraycopy(array, 0, newArray, 0, array.length);
}
// 从右向左循环,将元素逐个向右挪一位
for (int i = array.length - 1; i >= index; i--) {
newArray[i + 1] = newArray[i];
}
// 腾出来的位置插入 element
newArray[index] = element;
return newArray;
}
/**
* @param array 数组
* @param index 要删除的下标,默认有效
* 删除数组元素
*/
public static void deleteElement(int[] array, int index) {
// 将 index 之后的元素向前移动一位
for (int i = index; i < array.length - 1; i++) {
array[i] = array[i + 1];
}
// 为数组最后一位赋值为 0,占位
array[array.length - 1] = 0;
}
public static void main(String[] args) {
int[] array = new int[]{3, 1, 2, 5, 4, 9, 7, 2};
display(array);
readElement(array, 3);
updateElement(array, 3, 10);
display(array);
int[] newArray = insertElement(array, 3, 20);
display(newArray);
deleteElement(array, 3);
display(array);
}
}

961

被折叠的 条评论
为什么被折叠?



