Skip to content

链表

js
class LinkNode {
  constructor(data) {
    this.data = data
    this.next = null
  }
}

class LinkedList {
  head = null
  length = 0

  // 向链表尾部追加数据
  append(data) {
    const newNode = new LinkNode(data)
    // 链表为空,直接更新首节点
    if (this.length === 0) {
      this.head = newNode
    } else {
    // 链表不为空,遍历链表直到链表尾部(node.next为null)
      let currentNode = this.head
      while (currentNode.next) {
        currentNode = currentNode.next
      }
      currentNode.next = newNode
    }
    this.length++
  }

  // 在链表指定位置插入数据
  insert(position, data) {
    if (position < 0 || position > this.length) return new Error('索引越界')
    const newNode = new LinkNode(data)
    // 索引为0,直接更新首节点
    if (position === 0) {
      newNode.next = this.head
      this.head = newNode
    } else {
      // 索引大于0,则以索引为终点遍历链表;
      // 定义当前节点的上一个节点,遍历过程中不断更新当前节点,
      // 遍历结束后,将新插入的节点next引用指向当前节点,上一个节点next则指向新插入的节点,以此可得到 上个节点->新节点->旧的'当前节点',则新节点成功插入
      let index = 0
      let currentNode = this.head
      // 当前节点的上一个节点
      let prevNode = null
      while(index < position) {
        prevNode = currentNode
        currentNode = currentNode.next
        index++
      }
      newNode.next = currentNode
      prevNode.next = newNode
    }
    this.length++
    return newNode
  }

  // 移除指定位置的节点
  removeAt(position) {
    if (position < 0 || position > this.length) return new Error('索引越界')
    let currentNode = this.head
    // 索引为0,将当前的首节点替换为下一个节点
    if (position === 0) {
      this.head = currentNode.next
    } else {
      // 索引大于0,以索引为终点遍历链表;
      // 定义当前节点的上一个节点,将上一个节点的nex指向当前节点的next,则相当于在链表中移除了当前节点(因为链表中已无法再触达到当前节点,next引用已断开)
      let index = 0
      let prevNode = null
      while(index < position) {
        prevNode = currentNode
        currentNode = currentNode.next
        index++
      }
      prevNode.next = currentNode.next
    }
    // 断开被删除节点的链接;
    // tips: 此处可以不删除,为了避免垃圾回收机制失败后不能继续回收next引用的后续节点,删除更加安全
    currentNode.next = null
    this.length--
    return currentNode
  }

  // 删除指定数据的节点
  remove(data) {
    this.removeAt(this.findIndex(data))
  }

  // 更新链表指定位置的数据
  update(position, data) {
    if (position < 0 || position > this.length) return new Error('索引越界')
    if (position === 0) {
      this.head.data = data
      return
    }
    let index = 0
    let currentNode = this.head
    while(index < position) {
      currentNode = currentNode.next
      index++
    }
    currentNode.data = data
    return currentNode
  }

  // 查询数据在链表中的位置
  findIndex(data) {
    let index = 0
    let currentNode = this.head
    while(currentNode) {
      if (currentNode.data === data) return index
      currentNode = currentNode.next
      index++
    }
    return -1
  }

  // 根据索引查找链表中的数据
  findByIndex(position) {
    if (position < 0 || position > this.length) return new Error('索引越界')
    if (position === 0) {
      return this.head.data
    } else {
      let index = 0
      let currentNode = this.head
      while(index < position) {
        currentNode = currentNode.next
        index++
      }
      return currentNode?.data || null
    }
  }

  size() {
    return this.length
  }

  isEmpty() {
    return this.length === 0
  }

  // 以字符串形式输出链表数据
  toString() {
    let currentNode = this.head
    let res = ''
    while (currentNode) {
      res += currentNode.data + '->'
      currentNode = currentNode.next
    }
    return res
  }
}