数据结构与算法-数组

学习来源:极客时间王争老师的《数据结构与算法之美》

记录一下笔记及自己的感想

数组:是一种线性表数据结构,他用一组连续的内存空间,来存储一组具有相同类型的数据。

线性表:数据排成像一条线一样的结构,每个线性表上的数据最多只有前和后两个方向。

非线性表:比如二叉树、堆、图等。数据之间不是简单的前后关系。

连续的内存空间和相同类型的数据:可以随机访问,但是插入数据需要做大量的数据搬移工作。

数组如何实现根据下标随机访问数组元素?

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

a[i]_address = base_address + i * data_type_size

数组支持随机访问,根据下标随机访问的时间复杂度为O(1),如果用其他方式比如二分查找,时间复杂度也是O(logn)

插入和删除时间复杂度

插入操作

1.最好时间复杂度:如果在数组的末尾插入元素,则不需要移动数据,此时时间复杂度为O(1)

2.最坏时间复杂度:如果在数组开头插入元素,所有数据依次向后移一位,所以时间复杂度是O(n)

3.平均情况时间复杂度:因为在每个位置插入元素的概率一样,所以是(1/n + 2/n + … + n/n) = O(n).

4.如果忽略数组的连续性,可以将需要插入位置的元素,放到数组末尾,再将插入的元素直接放置,那时间复杂度就为O(1),处理思想在快速排序中也运用到。

比如: int a[5] = a b c d e

在a[2] = c的位置插入x ,先将a[5] = c 再将a[2] = x 即可

此时 int a[6] = a b x d e c

删除操作

1.最好时间复杂度:删除数组末尾的数据 O(1)

2.最坏时间复杂度:删除数组开头的数据 O(n)

3.平均情况时间复杂度: O(n)

4.如果不追求数组中的连续性,假设可以将多次删除操作集中在一起执行,删除效率会提高很多

比如a[10]中存储了8个元素:a b c d e f g h,现在需要删除a b c三个元素。为避免剩余的数据需要搬移3次,可以先记录下已经删除的数据。

每次删除并不是真正的搬移数据删除,记录某个数据已经被删除,当数组没有更多空间存储时,在执行一次真正删除操作。

举例:JVM标记清除垃圾回收算法的核心思想——新生代,老年代,当age=15时,会将对象放到老年代。

警惕数组访问越界问题

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;
}

以上C语言写的代码for循环的结束条件错写为i<=3,因此 当i=3时,arr[3]根据寻址公式,刚好为变量i的地址

因为变量在栈中从高地址到低地址分配,这里 i 和 arr数组是变量,所以由高到低:i,arr[3] =>数组内部是从低地址到高地址分配=>i,arr[2],arr[1],arr[0]

所以arr[3] == 变量i => i = 0 => 永远不满足循环停止条件 => 无线打印 hello world

很多计算机病毒也正是利用了代码中的数组越界可以访问非法地址的漏洞,来攻击系统。

容器是否能完全代替数组

ArrayList:

优势:

1.可以讲很多数组操作的细节封装

2.支持动态扩容

Arraylist每次空间不够时,会自动扩容为原来的1.5倍大小

因为扩容操作涉及内存申请和数据搬移,比较耗时,因此最好在创建ArrayList的时候事先指定数据大小

数组和容器的对比:

1.java ArrayList无法存储基本类型,比如int,long,需要封装为Integer,Long类,而自动装箱拆线有一定性能消耗。如果特别关注性能,或者使用基本类型,则选用数组。

2.如果数据大小事先已知,并且对数据的操作非常简单,用不到ArrayList提供的大部分方法,也可以直接使用数组。

3.使用多维数组时,会比容器更加直观,比如

int[] [] array;
ArrayList<ArrayList<int>> array;

总结

数组是一块连续存储空间,用来存储相同类型的数据,最大的特点是支持随机访问,但插入和删除操作比较低效,平均时间复杂度为O(n),平常业务开发可以使用封装了数组的容器,但底层开发还是直接使用数组更合适。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值