文章目录
一、数组介绍
数组是一种线性表,用连续的内存空间存储类型相同的数据元素。
像线性表、连续的内存空间都是什么意思呢?下面分别解释一下:
1、线性表
线性表的所有数据元素最多只有前和后两个方向的数据结构。
常见的线性表有数组、链表、队列、栈等。
非线性数据结构比较常见的是二叉树、图等。
2、连续的内存空间和类型相同的数据
在新建一个数组时,就会向内存申请一块连续的空间,这一块连续的空间会划分为相同大小的小块,在感觉上如下图所示:
因为放的是 int 类型数据,所以每块所占的内存的大小都为 4 字节。
正式因为数组有连续的内存空间和类型相同的数据,所以才拥有它最突出的特性。它支持利用下标进行随机访问。
二、利用数组实现插入操作及相应的时间复杂度分析
1、数组原本有顺序,插入后需要继续保持数组有序
(1)思路分析
首先为了保证插入后数组还是有序,需要找到数组应该插入的位置 k 。
找到插入位置 k 后,需要将 k ~ n - 1 个数组元素都向后移一位,将 k 的位置空下来。
然后插入元素即可。
(2)代码实现
/**
* 有序插入 (顺序为从小到大) 平均时间复杂度为 O(n),最好时间复杂度为 O(1),最坏时间复杂度为 O(n)
*
* @param e 被插入元素
*/
public void addOrdered(int e) throws RuntimeException {
// 判断是否已满,已满不能插入
if (getSize() == getCapacity()) {
throw new RuntimeException("当前数组元素已满,不能进行插入操作");
}
// 记录元素位置
int k = -1;
// 当前数组没有元素,直接插入
if (getSize() == 0) {
data[0] = e;
setSize(getSize() + 1);
return;
}
if (e < data[0]) {
k = 0;
} else if (e > data[getSize() - 1]){
k = getSize();
} else {
// 遍历数组找到元素顺序
for (k = 1; k < getSize(); k++) {
if (e < data[k]) {
break;
}
}
}
// 将 k ~ n - 1 的数向后挪
for (int i = getSize() - 1; i >= k; i--) {
data[i + 1] = data[i];
}
// 将 e 插入 k 位置
data[k] = e;
// 元素个数加 1
setSize(getSize() + 1);
}
(3)时间复杂度分析
最好时间复杂度为 O(1)(当需要将元素插入在数组末尾时,不需要挪动其他的数组元素)
最坏时间复杂度为 O(n)(当需要将元素插入在数组头部时,需要挪动 n - 1 个数组元素)
平均时间复杂度为 O(n)(可能插入的位置的概率都是一样的,为 1/n,所以平均时间复杂度为 (1 + 2 + … n) / n = O(n))
2、不需要保证数组的顺序,直接在数组末尾插入
(1)思路分析
由于不需要保证数组顺序,所以直接在数组末尾插入。
(2)代码实现
/**
* 插入元素到末尾 时间复杂度为 O(1)
* @param e
*/
public void add(int e) {
// 判断是否已满ÿ