返回

JavaScript 数据结构之链表,解剖之美

前端

链表的组成与特点

链表由一系列称为节点(Node)的元素组成,每个节点包含两个部分:

  • 数据域:存储实际的数据值。
  • 指针域:存储指向下一个节点的引用。

链表的第一个节点称为头节点(Head),它指向链表中的第一个数据节点,而最后一个节点称为尾节点(Tail),它的指针域为空,表示该节点之后没有更多的节点。

链表具有以下几个特点:

  • 链表是一种动态数据结构,这意味着它的大小可以根据需要增长或缩小。
  • 链表中的元素可以随机访问,但需要从头节点开始逐个遍历才能找到目标元素。
  • 链表中的元素可以轻松插入或删除,而不需要移动其他元素。

链表的实现

在 JavaScript 中,我们可以使用对象或数组来实现链表。

使用对象实现链表

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

class LinkedList {
  constructor() {
    this.head = null;
    this.tail = null;
    this.length = 0;
  }

  // 添加元素到链表尾部
  append(data) {
    const newNode = new Node(data);
    if (this.length === 0) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      this.tail.next = newNode;
      this.tail = newNode;
    }
    this.length++;
  }

  // 从链表头部移除元素
  removeFirst() {
    if (this.length === 0) {
      return null;
    }
    const removedNode = this.head;
    this.head = this.head.next;
    if (this.length === 1) {
      this.tail = null;
    }
    this.length--;
    return removedNode.data;
  }

  // 从链表中查找元素
  find(data) {
    let currentNode = this.head;
    while (currentNode !== null) {
      if (currentNode.data === data) {
        return currentNode;
      }
      currentNode = currentNode.next;
    }
    return null;
  }
}

使用数组实现链表

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

class LinkedList {
  constructor() {
    this.head = null;
    this.tail = null;
    this.length = 0;
  }

  // 添加元素到链表尾部
  append(data) {
    const newNode = new Node(data);
    if (this.length === 0) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      this.tail.next = newNode;
      this.tail = newNode;
    }
    this.length++;
  }

  // 从链表头部移除元素
  removeFirst() {
    if (this.length === 0) {
      return null;
    }
    const removedNode = this.head;
    this.head = this.head.next;
    if (this.length === 1) {
      this.tail = null;
    }
    this.length--;
    return removedNode.data;
  }

  // 从链表中查找元素
  find(data) {
    let currentNode = this.head;
    while (currentNode !== null) {
      if (currentNode.data === data) {
        return currentNode;
      }
      currentNode = currentNode.next;
    }
    return null;
  }
}

// 使用数组实现链表
class LinkedListArray {
  constructor() {
    this.data = [];
    this.length = 0;
  }

  // 添加元素到链表尾部
  append(data) {
    this.data.push(data);
    this.length++;
  }

  // 从链表头部移除元素
  removeFirst() {
    if (this.length === 0) {
      return null;
    }
    const removedData = this.data.shift();
    this.length--;
    return removedData;
  }

  // 从链表中查找元素
  find(data) {
    const index = this.data.indexOf(data);
    if (index === -1) {
      return null;
    }
    return this.data[index];
  }
}

链表的应用

链表在前端开发中有很多应用场景,例如:

  • 存储需要频繁增删改查的数据集合,例如购物车、播放列表等。
  • 实现栈和队列等数据结构。
  • 实现树和图等复杂数据结构。
  • 在虚拟 DOM 中,链表可以用来表示 DOM 树的结构。

链表的优缺点

链表具有以下优点:

  • 插入和删除元素非常高效,不需要移动其他元素。
  • 链表可以动态增长或缩小,不需要预先分配内存空间。

链表也有一些缺点:

  • 链表中的元素不能随机访问,需要从头节点开始逐个遍历才能找到目标元素。
  • 链表中的元素存储分散,可能会导致内存碎片。

总结

链表是 JavaScript 中一种重要的数据结构,它具有插入、删除和查找数据高效、存储空间动态分配的特点。在前端开发中,链表经常被用来存储需要频繁增删改查的数据集合、实现栈和队列等数据结构以及在虚拟 DOM 中表示 DOM 树的结构。希望本文能够帮助您更好地理解和使用链表。