• 链表的概念
  • 链表的实现
  • 链表的多种形式
  • LeeCode 题目

链表的概念

  • 链表是有序的数据结构, 链表中的每个部分称为节点
    • 可以在任意位置操作
    • 可以从首、尾、中间进行数据存取
  • 链表可以从首、尾、中间进行数据存取
  • 链表的元素在内存中不必时连续的空间
  • 优点:添加与删除不会导致其余元素位移
  • 缺点: 无法根据索引快速定位元素

为什么不直接使用数组?
某些操作中链表的性能要比数组好

  • 数组在内存中占用一段连续的空间
  • 添加、移除会导致后续元素位移,(操作非末尾的数据时)性能开销大

小结:

  • 获取、修改元素时, 数组效率高
  • 添加、删除元素时, 链表效率高

链表的实现

image.png
要实现以下功能:

  • 节点类: value、 next
  • 链表类:
    • addAtTail 尾部添加节点
    • addAtHead 头部添加节点
    • addAtIndex 指定位置添加节点
    • get 获取节点
    • removeAtIndex 删除指定节点

链表的实现

  1. class LinkedNode {
  2. constructor(value) {
  3. this.value = value
  4. this.next = null
  5. }
  6. }
  7. class LinkedList {
  8. constructor() {
  9. this.count = 0
  10. this.head = null
  11. }
  12. // 添加节点 尾
  13. addAtTail (value) {
  14. const node = new LinkedNode(value)
  15. if (this.count === 0) {
  16. this.head = node
  17. } else {
  18. let cur = this.head
  19. while(cur.next != null) {
  20. cur = cur.next
  21. }
  22. cur.next = node
  23. }
  24. this.count ++
  25. }
  26. // 添加节点 首
  27. addAtHead (value) {
  28. const node = new LinkedNode(value)
  29. if (this.count === 0) {
  30. this.head = node
  31. } else {
  32. node.next = this.head
  33. this.head = node
  34. }
  35. this.count ++
  36. }
  37. // 根据索引 获取节点
  38. get(index) {
  39. if (this.count === 0 || index< 0 || index >= this.count) {
  40. return
  41. }
  42. // 迭代链表, 找到对应节点
  43. let current = this.head
  44. for (let i = 0; i < index; i++) {
  45. current = current.next
  46. }
  47. return current
  48. }
  49. // 根据索引 添加节点
  50. addAtIndex(value, index) {
  51. if (this.count ===0 || index >= this.count) {
  52. return
  53. }
  54. // 如果 index <= 0 添加到头部
  55. if (index <= 0) {
  56. return this.addAtHead(value)
  57. }
  58. // 后面为正常区间处理
  59. const prev = this.get(index -1)
  60. const next = prev.next
  61. const node = new LinkedNode(value)
  62. prev.next = node
  63. node.next = next
  64. this.count++
  65. }
  66. // 删除
  67. removeAtIndex (index) {
  68. if (this.count === 0 || index < 0 || index >= this.count) {
  69. return
  70. }
  71. if (index === 0) {
  72. this.head = this.head.next
  73. } else {
  74. const prev = this.get(index -1)
  75. prev.next = prev.next.next
  76. }
  77. this.count--
  78. }
  79. }
  80. const l = new LinkedList();

链表的多种形式

常见的链表形式有:

  • 双向链表
  • 循环链表(环形链表)

    双向链表

    双向链表指的是在普通链表的基础上, 增加一个用于记录上一个节点的属性prev, 可进行双向访问
    image.png

循环链表(环形链表)

image.png

  • 循环链表又称为环形链表, 指的是链表最后一个节点的 next 指向第一个节点, 形成首尾相连的循环结构, 称为循环列表
  • 在实际使用中,环的结束点可以为链表的任意节点

反转链表