返回

从单向到双向:揭秘双向链表的奥秘

前端

在探索数据结构的奇妙世界时,我们早已结识了单向链表,它如同一条单行道,信息只能从头到尾或从尾到头流动。而今天,让我们踏上双向链表的征程,揭开它的独特魅力!

双向链表:双向通行的信息通道

双向链表与单向链表有着本质的区别,它是一种双向通行的信息通道。在双向链表中,每个节点除了指向下一个节点的指针外,还多了一个指向前一个节点 的指针,如同一条双车道公路,信息可以自由地从两端穿梭。

双向链表的优势:灵活性与效率

双向链表的双向通行性赋予了它独特的优势:

  • 高效查找: 双向指针允许从链表的任意位置快速查找元素,无论正向还是反向。
  • 便捷删除: 删除一个节点时,无需遍历整个链表,只需修改其前后指针即可。
  • 灵活插入: 在双向链表中插入一个新节点非常方便,因为我们可以从任一端进行插入。

双向链表的应用场景

双向链表在实际开发中有着广泛的应用:

  • 浏览器历史记录: 浏览器通过双向链表来记录用户的历史记录,用户可以轻松地前进或后退浏览。
  • 文本编辑器: 文本编辑器使用双向链表来存储文本,方便插入、删除和移动文本。
  • 虚拟内存管理: 操作系统使用双向链表来管理虚拟内存页面,实现高效的内存分配和释放。

实现双向链表:用代码构建

在 JavaScript 中,实现双向链表非常简单:

class Node {
  constructor(data) {
    this.data = data;
    this.next = null;
    this.prev = null;
  }
}

class DoublyLinkedList {
  constructor() {
    this.head = null;
    this.tail = null;
    this.size = 0;
  }

  // 添加节点到链表尾部
  append(data) {
    let newNode = new Node(data);
    if (this.head === null) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      this.tail.next = newNode;
      newNode.prev = this.tail;
      this.tail = newNode;
    }
    this.size++;
  }

  // 从链表中删除一个节点
  delete(node) {
    if (node === this.head) {
      this.head = node.next;
      if (this.head !== null) {
        this.head.prev = null;
      } else {
        this.tail = null;
      }
    } else if (node === this.tail) {
      this.tail = node.prev;
      if (this.tail !== null) {
        this.tail.next = null;
      } else {
        this.head = null;
      }
    } else {
      node.prev.next = node.next;
      node.next.prev = node.prev;
    }
    this.size--;
  }

  // 从链表中查找一个节点
  find(data) {
    let curr = this.head;
    while (curr !== null) {
      if (curr.data === data) {
        return curr;
      }
      curr = curr.next;
    }
    return null;
  }
}

拓展阅读: