带你读《图解算法小抄》二、双向链表(3)

简介: 带你读《图解算法小抄》二、双向链表(3)

带你读《图解算法小抄》二、双向链表(2)https://developer.aliyun.com/article/1348313?groupCode=tech_library

3DoublyLinkedList

export default class DoublyLinkedList {
  /**
   * @param {Function} [comparatorFunction]
   */
  constructor(comparatorFunction) {
    /** @var DoublyLinkedListNode */
    // 双向链表的头节点
    this.head = null;
    /** @var DoublyLinkedListNode */
    // 双向链表的尾节点
    this.tail = null;
    // 用于比较的函数
    this.compare = new Comparator(comparatorFunction);
  }
  /**
   * @param {*} value
   * @return {DoublyLinkedList}
   */
  // 将新的节点插入到头部
  prepend(value) {
    // 创建新的节点作为头部节点
    const newNode = new DoublyLinkedListNode(value, this.head);
    // 如果存在头部节点,那么它不再是头部节点了。
    // 因此,将其前驱节点设置为新节点(新的头部节点)。
    // 然后标记新的节点为头部节点。
    if (this.head) {
      this.head.previous = newNode;
    }
    this.head = newNode;
    // 如果还没有尾部节点,那么就让新的节点成为尾部节点。
    if (!this.tail) {
      this.tail = newNode;
    }
    return this;
  }
  /**
   * @param {*} value
   * @return {DoublyLinkedList}
   */
  // 将新的节点追加到尾部
  append(value) {
    const newNode = new DoublyLinkedListNode(value);
    // 如果还没有头部节点,让新的节点成为头部节点。
    if (!this.head) {
      this.head = newNode;
      this.tail = newNode;
      return this;
    }
    // 将新的节点添加到链表的末尾。
    this.tail.next = newNode;
    // 将当前尾部节点添加到新节点的前驱引用。
    newNode.previous = this.tail;
    // 设置新节点为链表的尾部节点。
    this.tail = newNode;
    return this;
  }
  /**
   * @param {*} value
   * @return {DoublyLinkedListNode}
   */
  // 删除具有特定值的节点
  delete(value) {
    if (!this.head) {
      return null;
    }
    let deletedNode = null;
    let currentNode = this.head;
    while (currentNode) {
      if (this.compare.equal(currentNode.value, value)) {
        deletedNode = currentNode;
        if (deletedNode === this.head) {
          // 如果要删除的是头部节点...
          // 将头部节点设置为第二个节点,它将成为新的头部节点。
          this.head = deletedNode.next;
          // 将新头部节点的前驱设置为 null。
          if (this.head) {
            this.head.previous = null;
          }
          // 如果链表中的所有节点的值都和传入的参数相同
          // 那么所有节点都会被删除,因此需要更新尾部节点。
          if (deletedNode === this.tail) {
            this.tail = null;
          }
        } else if (deletedNode === this.tail) {
          // 如果要删除的是尾部节点...
          // 将尾部节点设置为倒数第二个节点,它将成为新的尾部节点。
          this.tail = deletedNode.previous;
          this.tail.next = null;
        } else {
          // 如果要删除的是中间节点...
          const previousNode = deletedNode.previous;
          const nextNode = deletedNode.next;
          previousNode.next = nextNode;
          nextNode.previous = previousNode;
        }
      }
      currentNode = currentNode.next;
    }
    return deletedNode;
  }
  /**
   * @param {Object} findParams
   * @param {*} findParams.value
   * @param {function} [findParams.callback]
   * @return {DoublyLinkedListNode}
   */
  // 查找具有特定值或满足回调函数的节点
  find({ value = undefined, callback = undefined }) {
    if (!this.head) {
      return null;
    }
    let currentNode = this.head;
    while (currentNode) {
      // 如果指定了回调函数,那么尝试通过回调函数找到节点。
      if (callback && callback(currentNode.value)) {
        return currentNode;
      }
      // 如果指定了值,那么尝试通过值找到节点。
      if (value !== undefined && this.compare.equal(currentNode.value, value)) {
        return currentNode;
      }
      currentNode = currentNode.next;
    }
    return null;
  }
  /**
   * @return {DoublyLinkedListNode}
   */
  // 删除尾部节点
  deleteTail() {
    if (!this.tail) {
      // 没有尾部节点可以删除
      return null;
    }
    if (this.head === this.tail) {
      // 链表中只有一个节点
      const deletedTail = this.tail;
      this.head = null;
      this.tail = null;
      return deletedTail;
    }
    // 如果链表中有很多节点...
    const deletedTail = this.tail;
    this.tail = this.tail.previous;
    this.tail.next = null;
    return deletedTail;
  }
  /**
   * @return {DoublyLinkedListNode}
   */
  // 删除头部节点
  deleteHead() {
    if (!this.head) {
      return null;
    }
    const deletedHead = this.head;
    if (this.head.next) {
      this.head = this.head.next;
      this.head.previous = null;
    } else {
      this.head = null;
      this.tail = null;
    }
    return deletedHead;
  }
  /**
   * @return {DoublyLinkedListNode[]}
   */
  // 将链表转换为数组
  toArray() {
    const nodes = [];
    let currentNode = this.head;
    while (currentNode) {
      nodes.push(currentNode);
      currentNode = currentNode.next;
    }
    return nodes;
  }
  /**
   * @param {*[]} values - 需要转换为链表的值的数组。
   * @return {DoublyLinkedList}
   */
  // 从数组创建链表
  fromArray(values) {
    values.forEach((value) => this.append(value));
    return this;
  }
  /**
   * @param {function} [callback]
   * @return {string}
   */
  // 将链表转换为字符串
  toString(callback) {
    return this.toArray().map((node) => node.toString(callback)).toString();
  }
  /**
   * 反转链表。
   * @returns {DoublyLinkedList}
   */
  reverse() {
    let currNode = this.head;
    let prevNode = null;
    let nextNode = null;
    while (currNode) {
      // 存储下一个节点。
      nextNode = currNode.next;
      prevNode = currNode.previous;
      // 改变当前节点的下一个节点,使其链接到前一个节点。
      currNode.next = prevNode;
      currNode.previous = nextNode;
      // 将 prevNode 和 currNode 节点向前移动一步。
      prevNode = currNode;
      currNode = nextNode;
    }
    // 重置头部和尾部节点。
    this.tail = this.head;
    this.head = prevNode;
    return this;
  }
}

2. 复杂度

时间复杂度

Access

Search

Insertion

Deletion

O(n)

O(n)

O(1)

O(1)

空间复杂度

O(n)

3. 参考

Wikipedia

YouTube

相关文章
|
5天前
|
存储 算法 C语言
【数据结构与算法 刷题系列】合并两个有序链表
【数据结构与算法 刷题系列】合并两个有序链表
|
13天前
|
存储 算法 Go
算法学习:数组 vs 链表
算法学习:数组 vs 链表
17 0
|
6天前
|
机器学习/深度学习 算法 C语言
【C/数据结构与算法】:10道链表经典OJ
【C/数据结构与算法】:10道链表经典OJ
9 1
|
13天前
|
算法 Java
[Java·算法·中等] LeetCode21. 合并两个有序链表
[Java·算法·中等] LeetCode21. 合并两个有序链表
15 2
|
4天前
|
算法 Java
Java数据结构与算法:双向链表
Java数据结构与算法:双向链表
|
4天前
|
算法 Java
Java数据结构与算法:循环链表
Java数据结构与算法:循环链表
|
5天前
|
算法
【数据结构与算法 刷题系列】求带环链表的入环节点(图文详解)
【数据结构与算法 刷题系列】求带环链表的入环节点(图文详解)
|
5天前
|
算法
【数据结构与算法 刷题系列】判断链表是否有环(图文详解)
【数据结构与算法 刷题系列】判断链表是否有环(图文详解)
|
5天前
|
算法
【数据结构与算法 经典例题】随机链表的复制(图文详解)
【数据结构与算法 经典例题】随机链表的复制(图文详解)
|
5天前
|
算法 C语言
【数据结构与算法 经典例题】链表的回文结构(图文详解)
【数据结构与算法 经典例题】链表的回文结构(图文详解)