🎨
Notes
  • 持续更新中...
  • articles
    • browser
      • 深入理解现代浏览器 - 导航
      • 深入理解现代浏览器 - 架构
      • 深入理解现代浏览器 - 交互
      • 深入理解现代浏览器 - 渲染器进程
    • dsa
      • DSA - 并查集
      • DSA - 哈希表
      • DSA - AVL 树
      • DSA - 二叉树
      • 快速选择
      • Big O 算法复杂度
      • DSA - 栈和队列
      • DSA - 前缀树 Trie
      • DSA - 图
      • DSA - 链表
      • DSA - 递归
    • typescript
      • TypeScript 学习笔记 - 任意属性 (Indexable Types)
      • 力扣的 TypeScript 面试题
      • TypeScript 学习笔记 - as const
      • TypeScript 学习笔记 - infer
    • network
      • Internet Protocol (IP)
      • 计算机网络基础
      • 如何分辨同源和同站
      • DNS 如何查询 IP 地址?
    • vue
      • Nuxt.js 入门
      • 从零实现一个 Mini Vue
      • 从零实现一个简单的 VDOM 引擎
      • 从零实现一个响应式状态管理
    • sorting
      • 排序 - 归并排序
      • 排序 - 冒泡排序
      • 排序 - 选择排序
      • 排序 - 计数排序
      • 排序 - 插入排序
    • compile
      • Compiler and Interpreter
      • Just-In-Time (JIT) Compilers
      • 编译流程
    • others
      • 什么是上下文无关语法
      • 如何在终端打印出有颜色的字
    • dev-ops
      • github-actions
        • GitHub Action 简介
        • GitHub Actions for CI
    • workflow
      • 用 Node 写一个 cli
      • 如何规范 git commit 信息
      • 如何监听 git hooks
      • 如何规范代码风格 - prettier
      • 如何发布一个 npm package
      • 如何规范代码质量 - eslint
    • design-pattern
      • 代理模式
      • 单例模式
      • 策略模式
    • security
      • 点击劫持
      • CSP 内容安全策略
    • javascript
      • 尾调用优化
      • 4种常见的内存泄漏及解决方法
    • unit-test
      • Test Vuejs Application - Chapter 2
      • Test Vuejs Application - Chapter 1
      • Vue Unit Test Intro
    • performance
      • HTTP 缓存
      • 如何优化图片资源
Powered by GitBook
On this page
  • 简介
  • 基本操作
  • 链表 vs 数组
  • 考点
  • 指针的修改
  • 链表的拼接
  • 注意点
  • 技巧
  • 题目

Was this helpful?

  1. articles
  2. dsa

DSA - 链表

PreviousDSA - 图NextDSA - 递归

Last updated 4 years ago

Was this helpful?

简介

各种数据结构的底层实现都是数组和链表,数组和链表的根本区别在于它们使用内存的方式。

如果将计算机内存简单看成下图那样,每一个内存单元就是一个小格子。

可以看到,数组是需要连续空间的,而链表则不一定。

由于数组是连续的内存空间,因此:

  • 可以按下标随机访问,访问的时间复杂度是 $O(1)$。

  • 插入或者删除操作很麻烦,由于需要移动插入/删除元素后面的所有元素,时间复杂度平均是 $O(N)$。只有在数组尾部进行插入/删除操作时间复杂度才是 $O(1)$。

  • 总的来说,数组是【查询友好,插入/删除不友好】。

而链表不要求连续的内存空间,各个节点可以随意散落在内存中,节点之间通过 next 指针连起来就行,所以:

  • 需要通过遍历来查找某一个节点,访问的时间复杂度是 $O(N)$。

  • 插入或者删除操作很方便,插入操作只需要在内存中随便找一个空格子存节点数据,然后把原链表尾部节点的 next 指针指向这个格子就好了。删除则只需要把待删除节点的空间回收,并把指向它的指针改为指向下一个节点就行。

基本操作

  • 插入,给定节点插入位置的话,时间复杂度是 $O(1)$,否则还要遍历找到插入的节点位置,时间为 $O(N)$。

  • 删除,$O(1)$,如果要先找到删除节点,时间也是 $O(N)$。

  • 遍历,$O(N)$。

链表 vs 数组

都是线性的数据结构,只在细微的操作和使用场景上有差别。

考点

  1. 指针的修改

  2. 链表的拼接

指针的修改

典型的题目是 反转链表。

反转链表模板

反转任意一段链表:

JavaScript Code

// 反转一段子链表,并返回反转后新的头尾节点
function reverse(head, tail, terminal) {
    let prev = null,
        cur = head;

    while (cur !== terminal) {
        // 保存下一个节点,防止丢失
        const next = cur.next;
        // 修改指针
        cur.next = prev;

        // 继续前移
        prev = cur;
        cur = next;
    }
    // 反转后的新的头尾节点返回出去
    return [tail, head];
}

链表的拼接

比如反转链表 II,以及合并有序链表等。

注意点

  1. 环

  2. 边界

  3. 递归

技巧

  1. 虚拟头

  2. 快慢指针

题目

21. 合并两个有序链表
82. 删除排序链表中的重复元素 II
83. 删除排序链表中的重复元素
86. 分隔链表
92. 反转链表 II
138. 复制带随机指针的链表
141. 环形链表
142. 环形链表 II
143. 重排链表
148. 排序链表
206. 反转链表
234. 回文链表