定义
数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。
线性表
顾名思义,线性表就是数据排成像一条线一样的结构。每个线性表上的数据最多只有前和后两个方向。其实除了数组,链表、队列、栈等也是线性表结构。
image
image
连续内存,类型相同
image
我们知道,计算机会给每个内存单元分配一个地址,计算机通过地址来访问内存中的数据。当计算机需要随机访问数组中的某个元素时,它会首先通过下面的寻址公式,计算出该元素存储的内存地址:
a[i]_address = base_address + i * data_type_size
优劣
优点显而易见,其时间复杂度仅仅为 ,但是对于插入或者删除,都需要通过平移数组来完成操作,这就意味着最坏时间复杂度为
,如果容量还需要进行扩容,这是相当耗时的。
个人总结
- Java List 无法存储基本类型,都需要封住成 Integer 或者 Long 类,而装箱和拆箱是有很大的性能消耗的。
- 如果数据大小事先已知,并且对数据的操作非常简单,用不到 ArrayList 提供的大部分方法,也可以直接使用数组。
例子
- 普通数组封装(不支持扩容)
class Array {
int data[];
int count;
int n;
Array(int capacity) {
data = new int[capacity];
count = 0;
n = capacity;
}
boolean add(int index, int value) {
if (count >= n) {
System.out.println("容量达到最大值");
return false;
}
if (index > count) {
System.out.println("下标越界");
return false;
}
// 从屁股开始,往后移动,将 index 位置空出来
for (int i = count; i > index; i--) {
data[i] = data[i - 1];
}
data[index] = value;
count++;
System.out.println("插入成功:\tvalue:\t" + value + ":\tindex:\t" + index);
System.out.println("data:\t" + toString());
return true;
}
int get(int index) {
if (index >= count) {
return -1;
}
System.out.println("value:\t" + data[index]);
return data[index];
}
boolean delete(int index) {
if (index >= count) {
System.out.println("下标越界");
return false;
}
for (int i = index; i < count - 1; i++) {
data[i] = data[i + 1];
}
data[count - 1] = 0;
count--;
System.out.println("删除成功 data:\t" + toString());
return true;
}
@Override
public String toString() {
return Arrays.toString(data);
}
public static void main(String[] args) {
Array array = new Array(10);
array.add(0, 1);
array.add(1, 2);
array.add(2, 3);
array.add(3, 4);
array.add(4, 5);
array.add(5, 6);
array.add(6, 7);
array.add(7, 8);
array.add(8,9);
array.add(9,10);
array.delete(9);
System.out.println("get value:\t" + array.get(3));
}
}
输出结果:
插入成功: value: 1: index: 0
data: [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
插入成功: value: 2: index: 1
data: [1, 2, 0, 0, 0, 0, 0, 0, 0, 0]
插入成功: value: 3: index: 2
data: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0]
插入成功: value: 4: index: 3
data: [1, 2, 3, 4, 0, 0, 0, 0, 0, 0]
插入成功: value: 5: index: 4
data: [1, 2, 3, 4, 5, 0, 0, 0, 0, 0]
插入成功: value: 6: index: 5
data: [1, 2, 3, 4, 5, 6, 0, 0, 0, 0]
插入成功: value: 7: index: 6
data: [1, 2, 3, 4, 5, 6, 7, 0, 0, 0]
插入成功: value: 8: index: 7
data: [1, 2, 3, 4, 5, 6, 7, 8, 0, 0]
插入成功: value: 9: index: 8
data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
插入成功: value: 10: index: 9
data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
删除成功 data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
value: 4
get value: 4
- 支持扩容的数组
class GenericArray<T> {
T[] data;
int size;
GenericArray(int capacity) {
data = (T[]) new Object[capacity];
size = 0;
}
GenericArray() {
this(10);
}
void checkIndex(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("下标越界");
}
}
void resize(int newSize) {
T[] newData = (T[]) new Object[newSize];
for (int i = 0; i < size; i++) {
newData[i] = data[i];
}
System.out.println("扩容 capacity:\t" + newSize);
data = newData;
}
T get(int index) {
checkIndex(index);
return data[index];
}
boolean isEmpty() {
return size == 0;
}
void set(int index, T t) {
checkIndex(index);
data[index] = t;
System.out.println("set value:" + " index: " + index + " value: " + t);
System.out.println("data: " + toString());
}
int getCapacity() {
return data.length;
}
int getCount() {
return size;
}
boolean contains(T t) {
for (int i = 0; i < size; i++) {
if (data[i] == t) {
return true;
}
}
return false;
}
int find(T t) {
for (int i = 0; i < size; i++) {
if (data[i] == t) {
return i;
}
}
return -1;
}
void add(int index, T t) {
if (index < 0 || index > size) {
throw new IndexOutOfBoundsException("下标越界");
}
if (size == data.length) {
resize(2 * size);
}
for (int i = size; i > index; i--) {
data[i] = data[i-1];
}
data[index] = t;
size ++;
System.out.println("add data: " + " index: " + index + " value: " + t);
System.out.println("data: " + toString());
}
void addFirst(T t) {
add(0, t);
}
void addLast(T t) {
add(size, t);
}
T remove(int index) {
checkIndex(index);
T t = data[index];
for (int i = index; i < size - 1; i++) {
data[i] = data[i + 1];
}
data[size-1] = null;
size--;
if (size == data.length / 4 && data.length / 2 != 0) {
resize(data.length / 2);
}
System.out.println("remove data: " + " index: " + index + " value: " + t);
System.out.println("data: " + toString());
return t;
}
@Override
public String toString() {
return Arrays.toString(data);
}
public static void main(String[] args) {
GenericArray<String> data = new GenericArray<String>(6);
data.addLast("1");
data.addLast("2");
data.addLast("3");
data.addLast("4");
data.addLast("5");
data.addLast("6");
data.addLast("7");
data.remove(data.getCount()-1);
data.remove(data.getCount()-1);
data.remove(data.getCount()-1);
data.remove(data.getCount()-1);
}
}
输出结果:
add data: index: 0 value: 1
data: [1, null, null, null, null, null]
add data: index: 1 value: 2
data: [1, 2, null, null, null, null]
add data: index: 2 value: 3
data: [1, 2, 3, null, null, null]
add data: index: 3 value: 4
data: [1, 2, 3, 4, null, null]
add data: index: 4 value: 5
data: [1, 2, 3, 4, 5, null]
add data: index: 5 value: 6
data: [1, 2, 3, 4, 5, 6]
扩容 capacity: 12
add data: index: 6 value: 7
data: [1, 2, 3, 4, 5, 6, 7, null, null, null, null, null]
remove data: index: 6 value: 7
data: [1, 2, 3, 4, 5, 6, null, null, null, null, null, null]
remove data: index: 5 value: 6
data: [1, 2, 3, 4, 5, null, null, null, null, null, null, null]
remove data: index: 4 value: 5
data: [1, 2, 3, 4, null, null, null, null, null, null, null, null]
扩容 capacity: 6
remove data: index: 3 value: 4
data: [1, 2, 3, null, null, null]
参考自极客时间