概念
链表与数组相似,都是有序的线性结构,不过数组在内存空间中是连续的,而链表中的每一项——结点,则是离散的。
在链表中,每个结点包括两部分:数据域和指针域,指针域用来指向下一个结点。JS中的链表通过嵌套对象实现
{val: 1, // 数据域next: {val: 2,next: ...}}
链表结点的创建:
function ListNode(val) {this.val = val;this.next = null;}const node1 = new ListNode(1)node1.next = new ListNode(2)
链表元素的添加,删除
添加
任意两个结点之间添加一个新结点:
const node3 = new Listnode(3)node3.next = node1.next // 也就是 node2node1.next = node3
删除
任意两个结点之间删除一个结点:
由于链表的访问是单向的,只能通过 next 指针从前往后访问,所以删除 node3 的关键是找到它的前驱结点 node1,直接让 node1 的 next 指向 node3 的next(node2),node3 由于不再被引用,会被自动垃圾回收掉。
node1.next = node1.next.next
链表和数组的辨析
js 中的数组
大多数计算机语言中数组对应着一段连续的内存,假设数组的长度是 n ,那么增加/删除操作导致需要移动的元素数量与 n 成线性关系。所以数组的增加/删除操作对应复杂度是O(n)
但 js 中的数组未必是真正的数组
const arr1 = [1, 2, 3] // 真正的数组const arr2 = ['a', 1, {name: 'wy'}]
arr2 就不是真正的数组,内存不连续,其底层使用哈希映射分配内存空间,是由对象链表来实现的。
链表与数组的对比
- 增删操作高效:链表与数组对比,增删元素不需要挪动多余的元素,只需要改变指针的指向,与链表结点个数 n 无关,复杂度是常数级别O(1)
- 访问操作低效:数组中可以直接通过索引访问元素,复杂度是O(1)。链表中访问元素只能从头遍历结点,复杂度与链表结点个数 n 成线性关系,复杂度是O(n)
总结来说:链表的插入/删除效率高,而访问效率低。数组的访问效率高,插入/删除效率低。
