📋 文章大纲
一、开篇:为什么前端要学链表?
- 数组的痛:那些年我们一起搬过的数据
splice(2, 0, 99)三个参数:从哪里开始、删除几个元素、插入什么值- 你以为直接插入?大错特错!JS引擎先将索引2后面的元素全部往后挪一位,然后再把值加入当前数组,时间复杂度为O(arr.length-index)
// 1.向数组插入值
const array = [1, 2, 3, 4, 5];
array.splice(2, 0, 99);
console.log(array); // 输出:[1, 2, 99, 3, 4, 5]
- 链表的优雅:像火车车厢一样自由连接
- 链表要插入或删除一个值,直接将当前车厢和下一节车厢分开,然后加入新的车厢,再将新旧车厢相连,时间复杂度O(1),极大优化性能
- 请看图:
- 现实应用:React Fiber、Vue3响应式、浏览器历史记录
二、初识链表:数据结构界的"贪吃蛇"
- 从数组到链表:思维转换
- 数组通过下标访问数据,链表通过指针遍历节点
const array = [1, 2, 3, 4, 5];
array.splice(2, 0, 99);
console.log(array); // 输出:[1, 2, 99, 3, 4, 5]
console.log(array[2]); // 输出:99
-
节点概念:数据 + 指针 = 无限可能
- 链表由节点通过指针连接而成
- 访问数据需要从头节点开始,通过指针逐个遍历
- 编程中常用:
head代表头节点,head.next表示下一节点,value访问节点值
-
可视化理解:图示说明
三、算法解析:LeetCode精选
3.1 简单题:反转链表(206题)
- 反转链表的核心思路:改变每个节点的指向方向
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var reverseList = function(head) {
let prev = null;
let curr = head;
while (curr) {
const next = curr.next; // 保存下一个节点
curr.next = prev; // 反转当前节点的指向
prev = curr; // prev向前移动
curr = next; // curr向前移动
}
return prev; // 返回新的头节点
};
执行过程详解:
- 第一次循环
- 第二次循环
- 继续执行直到完成
- 最终返回prev,得到反转后的链表