JavaScript数据结构-链接列表的教程

67 阅读2分钟

链接列表是你能学到的最重要的数据结构之一。

在一个链接列表中,每个项目都包含一个对其后面项目的引用。

我们可以从列表的开头开始,即head ,然后遍历列表中的所有项目,直到我们到达终点(tail )。

与数组相比,项目在实际的内存中并不是彼此相邻的(在低级别的编程语言中),也没有我们可以用来随机访问数组中某一项目的索引。

我们不能引用列表中间的一个项目,而不从头开始,因为我们不知道如何去引用它。

JavaScript没有链接列表的实现,所以我们现在要创建一个。

首先,我们创建Item 类,它将成为列表中每个项目的容器。

class Item {
  next = null
  value = null
  constructor(value) {
    this.value = value
  }
}

我们有一个指向列表中下一个项目的指针,以及值。

然后我们定义了一个LinkedList 类,它将承载两个私有值:headtail

我们定义了一个append() 方法来向列表中添加一个项目。如果它是我们添加的第一个项目,那么这个项目既是列表的头也是列表的尾。否则,我们创建这个项目,并将其分配给尾部项目的next 属性。

class LinkedList {
  #head = null
  #tail = null
  append = (value) => {
    const item = new Item(value)
    if (!this.#head) {
      this.#head = item
      this.#tail = item
      return
    }
    this.#tail.next = item
    this.#tail = item
  }
  size = () => {
    let count = 1
    let item = this.#head
    if (!item) return 0
    while ((item = item.next)) {
      count++
    }
    return count
  }
}

这就是我们可以使用它的方法。

const list = new LinkedList()
list.append(1)
list.append(2)
list.append(3)

我们可以添加一个size() 方法来返回列表的大小。

class LinkedList {
  //...
  size = () => {
    let count = 1
    let item = this.#head
    if (!item) return 0
    while ((item = item.next)) {
      count++
    }
    return count
  }
}
const list = new LinkedList()
list.size() //0
list.append(1)
list.size() //1
list.append(2)
list.append(3)
list.size() //3

我们如何在列表中找到一个项目,通过值?让我们实现一个方法来做到这一点。

class LinkedList {
  //...
  find = (value) => {
    let count = 1
    let item = this.#head
    if (!item) return null
    while ((item = item.next)) {
      if (item.value === value) {
        return item
      }
    }
    return null
  }
}

const list = new LinkedList()
list.append(1)
list.append(2)
list.append(3)
const item = list.find(2) //item.value === 2

如果我们想在链表中插入一个项目呢?我们已经有append() ,在列表的末尾插入项目。让我们实现一种方法,在一个特定的位置插入项目。

class LinkedList {
  //...
  insert = (index, value) => {
    //check for out-of-bounds values
    if (index < 0 || index > this.size()) return

    const node = new Item(value)
    let current = this.#head
    let previous

    if (index === 0) {
      //first position
      node.next = current
      this.#head = node
    } else {
      let i = 0
      while (i++ < index) {
        previous = current
        current = current.next
      }
      node.next = current
      previous.next = node
    }
  }
}

const list = new LinkedList()
list.append(1)
list.append(2)
list.append(3)
list.insert(2, 'a')
list.size() //4

另一种类型的链表是双链表,其中每个项目也包含一个到前一个元素的链接。