数组相关

数组指的是线性列表,在内存中是一段连续的内存空间,存储的数据类型一致

两个特点:

1)线性表,线性表就是数据排成像一条线一样的结构,每个线性表的数据最多只有前和后两个方向;

除了数组,链表、队列、栈等也是线性表结构。与它相对立的概念是非线性表,比如二叉树、堆、图等。之所以叫非线性表,是因为,在非线性表中,数据之间并不是简单的前后关系。

2)连续的内存空间和相同的数据类型,所以它可以“随机访问”,但因此它的增删操作都很低效,每次增或删为了保持连续性就需要做大量的数据搬移工作。

随机访问实现

如图,用一个长度为10的int类型数组,假设内存首地址base_address为1000,计算机分配的内存空间为1000~1039。

计算机会给每一个内存单位分配地址,计算机通过地址来访问内存中的数据,当需要随机访问数组中的某一元素时,它会首先通过寻址公式计算出元素存储的内存地址:

a[i]_address = base_address + i * data_type_size

其中i为元素下标,data_type_size表示数组中元素大小。该数组中元素类型为int,所以data_type_size大小为4个字节。

此处记录一下为什么数组都是从0下标开始?

因为当下标从1开始时,寻址公式就变为:

a[i]_address = base_address + (i-1) * data_type_size

这样每次随机访问数组都多了一次减法运算,cpu就会多出一次减法指令。数组作为非常基础的数据结构,通过下标随机访问数组元素又是其非常基础的变成操作,效率优化需要尽可能做到极致。

时间复杂度:数组支持随机访问,根据下标随机访问的时间复杂度为O(1)。

===============================================================

低效的插入和删除操作

插入:当数组长度为n,需要在k的位置插入数据,为了把第k位置空出来,需要将k~n的元素都顺序地向后移动一位。当插入的位置时末位则时间复杂度为O(1),如果是首位或者其他位置,其后的元素将向后移动,最坏时间复杂度为O(n),因为每个位置元素插入的概率都相同,平均时间复杂度为(1+2+···+n)/n = O(n);

删除:同上,若删除第k位元素,为了保持数组内存的连续性,同样需要移动元素。与插入类似,删除末位,是最优时间复杂度O(1),删除第k位元素,最坏时间复杂度位O(n),平均时间复杂度位O(n)。

注:

1)插入操作时,若数组对元素的顺序没有要求(无序),那么可以将要k对应的元素直接移到末位,然后将新元素直接插入k位置。特殊情况下,时间复杂度为O(1)。

2)删除操作时,若对数组中要删除的元素进行记录暂不删除,每次的删除操作并不是真正地搬移数据只是记录数据已经被删除,等到数组没有更多空间存储数据时,再触发执行一次真正的删除操作,这样就大大减少了数据搬移。(JVM标记清除垃圾回收算法

=================================================================

警惕数组的访问越界问题
用C语言循环越界访问的例子说明访问越界的bug。

int main(int argc, char* argv[]){
    int i = 0;
    int arr[3] = {0};
    for(; i<=3; i++){
        arr[i] = 0;
        printf("hello world\n");
    }
    return 0;
}

这段代码的运行结果并非是打印三行“hello word”,而是会无限打印“hello world”。

当然再java中不会出现这样的问题而是直接抛出java.lang.ArrayIndexOutOfBoundsException异常。

对于c这个情况,内存地分配是栈结构向下增长的,首先压栈的i,a[2],a[1],a[0],当访问到a[3]时,是在访问i变量,此时i变量的地址是数组当前进程的,所以修改时操作系统不会终止进程。

有个例子很形象:在Excel中从上往下拉4个格子,变量i会先被分配到第4个格子的内存,然后变量arr往上数分配3个格子的内存,但arr的数据是从分配3个格子的第一个格子从上往下存储数据的,当访问第3索引时,这时刚好访问到第4个格子变量i的内存。而a[3]=0就相当于i=0,于是陷入无限循环。

================================================================================

用数组还是容器?
数组先指定了空间大小
容器如ArrayList可以动态扩容。
1.希望存储基本类型数据,可以用数组
2.事先知道数据大小,并且操作简单,可以用数组
3.直观表示多维,可以用数组
4.业务开发,使用容器足够,开发框架,追求性能,首先数组。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值