数组
-
数组是一种线性的结构
-
在数据中的内存地址是连续的,这也就是在数组中为什么要指定数组的大小,只有在连续空间内数组才能成立。
-
在一个数组里面存储的数据结构都是相同的
数组的特点
下图是int[] a = new int[10] 数组结构。在下图可以看到数组的内存地址都是连续的。由于int
在Java占用4个字节。可以看到 每个空间都占用4个字节。
当数组进行插入操作时,需要将插入位置的元素整体向后移动一位,int[3] 到**int[6] **的位置都要像后面移动一位,所以说数组在进行插入操作时是比较耗时的。当数组需要在第一位插入元素时,数组的需要整体向后移动,时间复制度就会变成O(n)
,当数组在最后一位时数组的时间复制度就是O(1)
,所以数组的评价时间复制度位O(n/2)
,也是就是O(N)
。
当数组需要删除操作时,也需要进行数据数据的移动,时间时间复制度也是O(n)
在Java中ArrayList 也是通过数组实现的,ArrayList最大的优势就是将很多数组的操作的细节封装起来和动态扩容。
在使用ArrayList时如果可以需要使用的大小可以给ArrayList设置初始值,省掉很多次内存申请和数据搬移操作,避免在扩容时消耗掉部分性能。
数组的基本操作
public class ArraysTest {
private int size;
private int[] data;
private int index; //当前以存的数据大小
public ArraysTest(int size) {
this.size = size;
this.data = new int[size];
this.index =0;
}
public void print(){
for (int i = 0; i < size ; i++) {
System.out.printf(data[i]+" ");
}
}
//插入元素
public void insert(int loc,int n){
if (index++ < size){
for (int i = size -1; i > loc ; i--) {
data[i] = data[i-1];
}
data[loc] = n;
}
}
public void delete(int loc){ //O(n)
for(int i = loc ; i < size ; i++){
if(i != size - 1){ //怕越界所以加一个判断
data[i] = data[i + 1];
}else{
data[i] = 0; //默认为0 就是没存数据的
}
}
index -- ;
}
public void update(int loc,int n){
data[loc] = n;
}
public int get(int loc){
return data[loc];
}
}
为什么大部分的数组的起始位是0
在数组存储的内存模型上可以看到,数组的 下标 最准确的定义应该是 偏移(offset)。如果用a来表示数组的首先地址,a[0]的偏移位置为0的位置,也是a[k]表示偏移k个 type_size 的位置,在计算a[k]的内存地址只需要使用这个公式:
a[k] _address = base_address + k * type_size
如果数组是从1开始,那么a[k]的计算方式就是
a[k] _address = base_address + (k -1)* type_size
当每次进行访问时,数组元素就会多了一次减法运算,对于cpu来说,就是多了一次减法运算。
C 语言设计使用0作为数组的下标,在之后其他语言都模仿了C 语言,在设计上就可以减低学习成本。