📜  用Javascript实现LinkedList(1)

📅  最后修改于: 2023-12-03 15:11:14.736000             🧑  作者: Mango

用Javascript实现LinkedList

LinkedList,也称为链表,是一种常用的数据结构。它由一系列节点组成,每个节点包含数据和指向下一个节点的地址。相比于Array,LinkedList在插入和删除元素时更加高效,但是访问元素时则需要遍历整个链表。

实现

我们可以用Javascript来实现LinkedList。首先,我们需要定义一个Node类来表示每个节点:

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

每个Node对象包含一个value属性和一个next属性,分别表示节点的值和下一个节点的地址。

接下来,我们定义一个LinkedList类来管理整个链表:

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

LinkedList类有三个属性:head表示链表的头节点,tail表示链表的尾节点,length表示链表的长度。

我们可以实现以下几个方法来操作LinkedList:

append

append方法用于在链表的末尾添加一个节点。具体实现如下:

append(value) {
  const node = new Node(value);
  if (!this.head) {
    this.head = node;
    this.tail = node;
  } else {
    this.tail.next = node;
    this.tail = node;
  }
  this.length++;
}

append方法首先创建一个新的Node对象,然后判断链表是否为空。如果链表为空,将head和tail都指向新创建的节点。否则,将tail节点的next属性指向新创建的节点,并将tail指向新创建的节点。最后,链表长度加1。

insert

insert方法用于在链表的任意位置插入一个节点。具体实现如下:

insert(index, value) {
  if (index < 0 || index > this.length) {
    throw new Error('Index out of range');
  }
  const node = new Node(value);
  if (index === 0) {
    node.next = this.head;
    this.head = node;
    if (!this.tail) {
      this.tail = node;
    }
  } else if (index === this.length) {
    this.tail.next = node;
    this.tail = node;
  } else {
    let i = 0;
    let prev = null;
    let current = this.head;
    while (i < index) {
      prev = current;
      current = current.next;
      i++;
    }
    prev.next = node;
    node.next = current;
  }
  this.length++;
}

insert方法首先判断index是否合法,即是否在链表范围内。然后创建一个新的Node对象。如果index为0,即在链表头插入节点,将新创建的节点的next属性指向head节点,然后将head指向新创建的节点。如果链表为空,同时也将tail指向新创建的节点。如果index等于链表长度,即在链表末尾插入节点,将tail节点的next属性指向新创建的节点,并将tail指向新创建的节点。否则,遍历链表找到index位置的节点,将新创建的节点插入到前一个节点prev和后一个节点current之间。最后,链表长度加1。

remove

remove方法用于删除链表中某个节点。具体实现如下:

remove(index) {
  if (index < 0 || index >= this.length) {
    throw new Error('Index out of range');
  }
  let deletedNode = null;
  if (index === 0) {
    deletedNode = this.head;
    this.head = this.head.next;
    if (this.length === 1) {
      this.tail = null;
    }
  } else if (index === this.length - 1) {
    let current = this.head;
    let prev = null;
    while (current !== this.tail) {
      prev = current;
      current = current.next;
    }
    deletedNode = current;
    prev.next = null;
    this.tail = prev;
  } else {
    let i = 0;
    let prev = null;
    let current = this.head;
    while (i < index) {
      prev = current;
      current = current.next;
      i++;
    }
    deletedNode = current;
    prev.next = current.next;
  }
  this.length--;
  return deletedNode.value;
}

remove方法首先判断index是否合法,同样是在链表范围内。然后遍历链表找到index位置的节点。如果index为0,即要删除链表头节点,将head指向head节点的next属性,并将被删除的节点返回。如果链表长度为1,同样将tail指向null。如果index为链表长度减1,即要删除链表尾节点,需要遍历链表找到尾节点前一个节点prev,将prev的next属性指向null,并将tail指向prev节点。如果index为中间节点,那么需要遍历链表找到被删除节点的前一个节点prev和后一个节点current,将prev的next属性指向current的next属性,再将被删除的节点返回。最后,链表长度减1。

get

get方法用于查找链表中某个节点的值。具体实现如下:

get(index) {
  if (index < 0 || index >= this.length) {
    throw new Error('Index out of range');
  }
  let i = 0;
  let current = this.head;
  while (i < index) {
    current = current.next;
    i++;
  }
  return current.value;
}

get方法同样判断index是否合法。然后遍历链表找到index位置的节点,并返回节点的value属性。

indexOf

indexOf方法用于查找链表中某个节点的位置。具体实现如下:

indexOf(value) {
  let i = 0;
  let current = this.head;
  while (current) {
    if (current.value === value) {
      return i;
    }
    current = current.next;
    i++;
  }
  return -1;
}

indexOf方法遍历整个链表查找值为value的节点。如果找到了,返回节点的位置。否则,返回-1。

示例

我们来看一个简单的示例,创建一个LinkedList对象,然后添加几个节点,最后输出链表的长度和各节点的值:

const list = new LinkedList();
list.append(1);
list.append(2);
list.append(3);
list.insert(2, 4);
list.remove(1);
console.log(list.length); // 3
console.log(list.get(0)); // 1
console.log(list.get(1)); // 4
console.log(list.get(2)); // 3
console.log(list.indexOf(4)); // 1
console.log(list.indexOf(5)); // -1

输出结果如下:

3
1
4
3
1
-1
总结

LinkedList是一种常用的数据结构,用Javascript实现LinkedList可以加深对数据结构和算法的理解。在实现LinkedList时,需要注意几个问题:

  • 链表的头节点和尾节点需要分别记录
  • 添加、插入、删除节点时需要考虑链表是否为空、链表长度、节点的前一个和后一个节点
  • 访问节点时需要遍历整个链表,访问效率比Array低
  • 需要判断index是否合法,防止访问越界
  • 坚持使用链表而不是Array来处理适合链表的问题