《数据结构与算法之美》笔记——数组

最近又加了一个学习小组,准备开始快乐的刷力扣啦~

这类文章也会慢慢形成一个 leetcode 刷题系列的

今天就先从最简单的数组开始叭,理论部分我看的是王争老师的《数据结构与算法之美》,这是《数据结构与算法之美》的第一篇笔记~

1 数组定义

  • 数组是一种线性数据结构,用连续的存储空间存储相同类型数据

  • 线性表:数组、链表、队列、栈

    非线性表:树、图

  • 连续的内存空间、相同的数据,所以数组可以随机访问;但对数组进行删除、插入时,为了保证数组的连续性,就要做大量的数据搬移工作

2 数组实现随机访问

  • 数组如何实现下标随机访问?
    引入数组在内存中的分配图,得出寻址公式。

  • 纠正数组和链表的错误认识。

    数组的查找操作时间复杂度并不是O(1)。即便是排好的数组,用二分查找,时间复杂度也是O(logn)。
    正确表述:数组支持随机访问,根据下标随机访问的时间复杂度为O(1)

3 低效的插入和删除

  • 插入:最好 O(1) 最坏 O(n) 平均 O(n)
    插入:数组若无序,插入新的元素时,可以将第 K 个位置元素移动到数组末尾,把新的元素,插入到第 k 个位置,此处复杂度为 O(1)。
  • 删除:最好 O(1) 最坏 O(n) 平均 O(n)
    多次删除集中在一起,提高删除效率。
    记录下已经被删除的数据,每次的删除操作并不是搬移数据,只是记录数据已经被删除,当数组没有更多的存储空间时,再触发一次真正的删除操作。例如 Java 的 JVM 的垃圾回收算法。

4 警惕数组的访问越界问题

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”!

原因:

这里要了解栈这个东西。栈是向下增长的,首先压栈的 i,arr[2],arr[1],arr[0]。相当于访问 arr[3] 的时候,是在访问i变量,而此时 i 变量的地址是数组当前进程的,所以进行修改的时候,操作系统并不会终止进程。

5 容器能否完全替代数组

相比于数字,Java 中的 ArrayList 封装了数组的很多操作,并支持动态扩容一旦超过预先设定的容量,就需要扩容,扩容时比较耗内存,因为涉及到内存申请和数据搬移
数组适合的场景:

  • Java ArrayList 的使用涉及装箱拆箱,有一定的性能损耗,如果特别关注性能,可以考虑数组
  • 数据大小事先已知,并且涉及的数据操作非常简单,可以使用数组。
  • 表示多维数组时,数组往往更加直观。
  • 业务开发,直接使用容器就足够了,省时省力。毕竟损耗一丢丢性能,完全不会影响到系统整体的性能。如果是做一些非常底层的开发,比如开发网络框架,性能的优化需要做到极致,这个时候数组就会优于容器,成为首选。

6 为什么数组要从 0 开始编号,而不是从 1 开始呢

  • 从偏移角度理解 a[0]

  • 为什么循环要写成for(int i = 0;i<3;i++) 而不是for(int i = 0;i<=2;i++)

    因为第一个直接就可以算出 3 - 0 = 3 有三个数据,而后者 2-0+1 个数据,多出 1 个加法运算,很恼火。

  • 也有一定的历史原因

欢迎关注微信公众号 shinerise,与你一起慢慢进步~

Alt

发布了34 篇原创文章 · 获赞 9 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/Shine_rise/article/details/103939388
今日推荐