目录
前言
链表与数组的比较是转行新手或者应届生面试中比较老生常谈的问题了,各种面经已经写烂了的知识点到处都是,今天我就讲点那些面经很少写过的知识点,回答出来保证让你在面试官面前大涨眼缘,(写烂了的那些点也会对比整理放到后面。)
大涨眼缘的知识点(空间局部性原理也是导致数组访问更快的原因之一)
针对空间局部性原理,cpu访问内存中的数据并不是一个一个读取的,而是一块一块读取的,即会读取到目标位置附近的其他数据。
因此,在访问内存中的数据时,由于数组的元素在物理上是相邻的,在进行大量元素的访问时,数组元素的缓存命中率会高于链表元素的缓存命中率。
简单通俗的说就是这样一个例子:现在有一个链表和一个数组都存了10000个元素,访问元素时都使用顺序访问(抹除了数组可以随机访问的优势),数组的访问速度一样会比链表快。这就是CPU的数据读取策略造成的访问速度差异,也是空间局部性原理的体现。
可以简单总结为一句话:数组这种数据结构和CPU的契合度更高。
局部性原理的其他细节
什么是空间局部性和时间局部性?
- 空间局部性原理: 当一个存储单元被访问后,其附近单元在不久的将来也很可能被访问。形象地说,就是程序在访问某个数据项后,很可能会接着访问相邻的数据项。
- 时间局部性原理: 当一个存储单元被访问后,它在不久的将来很可能再次被访问。也就是说,程序在最近刚刚访问过的一个存储单元,很快又会再次访问它。
空间局部性原理为什么会对二者的访问速度造成差异
-
空间局部性的特点:
- 数据组织形式的影响: 数组、结构体等连续存储的数据结构更能体现空间局部性。
- 程序访问模式的影响: 顺序访问、循环访问等访问方式更有利于发挥空间局部性。
- 缓存的利用: 缓存系统的设计充分利用了空间局部性,将被访问的数据和其附近的存储单元一起加载到缓存中,提高访问速度。
-
时间局部性特点:
- 循环结构的影响: 循环结构中,循环体内的代码会被重复执行,导致循环变量和循环体内使用的变量被多次访问。
- 函数调用栈的影响: 函数调用时,函数的返回地址、局部变量等信息会被压入栈中,函数返回时又被弹出,这些数据会被多次访问。
- 变量的作用域的影响: 局部变量通常被频繁访问,全局变量则相对较少。
-
二者的联系:
- 互为补充: 空间局部性和时间局部性往往是同时存在的。例如,在循环访问数组元素时,既体现了空间局部性(连续访问数组元素),又体现了时间局部性(循环变量被多次访问)。
- 共同作用: 两种局部性共同作用,可以提高程序的执行效率。通过合理的数据组织和算法设计,可以充分利用局部性原理,减少内存访问次数,提高缓存命中率。
两种局部性在计算机系统中的应用
- 缓存设计: 缓存系统的设计充分利用了局部性原理,将最近被访问的数据和其附近的存储单元一起加载到缓存中,提高访问速度。
- 虚拟内存管理: 虚拟内存管理系统通过页面置换算法,将具有较强局部性的页面保留在内存中,减少页面调度次数。
- 编译优化: 编译器可以通过分析程序的局部性特征,进行代码优化,例如指令重排序、寄存器分配等。
- 并行计算: 并行计算中,通过数据划分和任务分配,可以充分利用局部性,减少通信开销。
局部性原理总结
空间局部性和时间局部性是程序运行过程中普遍存在的现象,理解和利用这些原理对于提高程序性能具有重要意义。通过合理的数据组织、算法设计和硬件优化,可以充分发挥局部性原理,提高程序的执行效率。
链表与数组的区别(老生常谈之整理对比版)
链表和数组是两种基础的数据结构,在存储数据方面各有优劣。
1. 存储方式
- 数组: 数组中的元素在内存中连续存储,占据一段连续的内存空间。
- 链表: 链表中的元素在内存中可以不连续,每个元素(节点)除了存储数据外,还存储了指向下一个节点的指针。
2. 访问方式
- 数组: 数组可以通过下标随机访问任意元素,访问速度快。
- 链表: 链表只能从头节点开始,一个接一个地访问元素,访问速度较慢,需要遍历。
3. 插入和删除
- 数组: 在数组中插入或删除元素需要移动大量元素,效率较低,尤其是当插入或删除位置靠近数组头部时。
- 链表: 在链表中插入或删除元素只需要修改指针,效率较高,特别适合频繁插入和删除操作。
4. 内存空间
- 数组: 数组需要预先分配连续的内存空间,如果元素个数不确定,可能导致内存浪费或溢出。
- 链表: 链表可以动态地分配内存,根据需要增加或减少节点,内存利用率较高。
5. 长度
- 数组: 数组的长度在定义时固定,不能动态改变。
- 链表: 链表的长度可以动态改变,可以随时插入或删除节点。
6. 适用场景
- 数组: 适合随机访问频繁,插入删除不频繁,且数据量相对固定的情况。例如:用数组实现栈、队列等数据结构。
- 链表: 适合插入删除频繁,随机访问不频繁,数据量动态变化的情况。例如:用链表实现队列、栈、图等数据结构。
7. 其他
- 数组占用内存连续,缓存局部性好,在某些情况下可能比链表具有更好的性能。
- 链表更加灵活,但由于指针的存在,内存管理也更加复杂,容易出现内存泄漏等问题。
总结
特性 | 数组 | 链表 |
---|---|---|
存储方式 | 连续存储 | 非连续存储,通过指针链接 |
访问方式 | 随机访问,下标访问 | 顺序访问,从头节点开始遍历 |
插入删除 | 效率低,需要移动大量元素 | 效率高,修改指针即可 |
内存空间 | 预先分配,可能浪费或溢出 | 动态分配,利用率高 |
长度 | 固定 | 动态 |
何时选择数组,何时选择链表?
- 如果需要频繁随机访问元素,且数据量相对固定,选择数组。
- 如果需要频繁插入删除元素,且数据量动态变化,选择链表。
- 如果对内存空间利用率要求较高,选择链表。
- 如果对缓存局部性要求较高,选择数组。