数组

数组特性:

1.线性表(包括数组、链表、队列和栈等)
2.连续内存空间和相同类型数据。

基于特性2:连续的内存空间和相同类型数据:

1.让数组具有随机访问特性。
2.为保证连续性,插入和删除数据可能会做大量数据搬移工作。

理解:随机访问特性(根据下标进行访问)

1.基于公式:a[i]_address=base_address + i*data_type_size。所以时间复杂度为O(1)。
2.注意:查找某个元素的时间复杂度不是O(1),对于排好序的数组二分查找(折半查找)时间复杂度也是O(logn)。

理解:插入操作(注意思考分配内存不足的问题)

1.尾部插入时间复杂度是O(1)(最好情况时间复杂度)。
2.头部插入时间复杂度为O(n)(最坏情况时间复杂度)。
3.平均时间复杂度(1+2+3+...+n)/n=O(n)。
4.优化方式:
  不需要保证稳定性的情况下将插入位置的数据放在最后,然后再插入数据。
  对于连续插入可以一次性插入。

理解:删除操作

1.尾部删除时间复杂度O(1)(最好)。
2.头部删除时间复杂度O(n)(最坏)。
3.优化方式:
   特殊场景下,不一定追求数据连续性,可以将多次删除集中为一次操作,减少数据搬移。类比java中JVM标记-清除算法的思想。

警惕数组越界

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代码中,由于人为失误:导致数组越界,数组越界造成了无限循环。对于不同编译器,在分配内存时,会按照内存地址递增或递减的方式进行分配。上面按照递减方式进行会出现无限循环。

    在 C 语言中,只要不是访问受限的内存,所有的内存空间都是可以自由访问的。根据我们前面讲的数组寻址公式,a[3] 也会被定位到某块不属于数组的内存地址上,而这个地址正好是存储变量 i 的内存地址,那么 a[3]=0 就相当于 i=0,所以就会导致代码无限循环。

说说数组和链表

1.数组对内存要求较高,需要连续。
2.链表需要额外的空间存指定地址。
3.数组由于连续内存空间和相同类型数据具有随机访问特性(n(1))。
4.链表更适合插入删除。在无法保证连续的大的内存空间的时候适合使用。性能更好。

Java中数组和容器ArrayList各自优缺点对比

1.ArrayList封装了数组操作中的细节,如:在插入删除过程中数据的搬移。
2.ArrayList支持动态扩容。这些细节不需要我们实现。注意:扩容涉及内存申请和数据搬移,比较耗时,建议创建ArrayList的时候就指定数据大小。

3.数组中如果需要更大的空间,将原来的数据复制进去,然后再将新的数据插入进行。这些需要我们来做。

4.ArrayList无法存储基本类型,需要基础类型的包装类,拆箱装箱需要一定性能消耗。希望使用基本数据类型就用数组。
5.针对二维数组或多维数组,Object[][]array比ArrayList<ArrayList>array更直观。

总结:对于业务开发用容器省时省力,损失性能不大,对底层开发对性能要求高的数组优于容器。

数组相关code:https://github.com/wangzheng0822/algo/tree/master/java/05_array

数据结构和算法,你如果不接触可能以后都不会接触,但是你接触了,你就会感觉到它的好。
数据结构和算法建议大家可以看看这个专栏老师写的很好,很感谢他:http://gk.link/a/103WJ

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容