js数据结构之链表

124 阅读3分钟

开车群在文末

链表存储有序的元素集合,但是不同于数组,链表中的元素在内存中并不是连续放置的

每个元素由一个存储元素本身的节点和一个指向下一个元素的引用组成

相对于传统的数组,链表的好处在于,添加和移除元素的时候不需要移动其他元素

链表需要指针

function defaultEquals (a, b) {
  return a === b;
}

class Node {
  constructor(element) {
    this.element = element;
    this.next = undefined;
  }
}
/**
 * 1、count:这是用来存储链表中的元素数量
 * 2、defaultEquals = equalsFn:这个方法来比较链表中的元素是否相等,为了找到链表中一个特定的元素
 * 3、head:因为链表的数据结构是动态的,需要将第一个元素的引用保存下来
 * 4、node:node类表示我们想要添加到链表中的项;这个类包含一个element属性,该属性表示要加入链表的值,以及一个next属性,这个属性是指向链表中下一革元素的指针。
 */
class LinkedList {
  constructor(equalsFn = defaultEquals) {
    this.count = 0;
    this.head = undefined;
    this.equalsFn = equalsFn;
  }
}

push方法

  push (element) {
    const node = new Node(element);
    let current;
    if (this.head == null) {
      this.head = node;
    } else {
      current = this.head;
      while (current.next != null) {
        current = current.next;
      }
      current.next = node;
    }
    this.count++;
  }

代码解释:

一、首先需要做的就是把element作为值传入,用node类来接收

const node = new Node(element);

二、当向空的列表中去添加一个元素的时候

1、创建一个linkedList对象,head会指向undefined(或者是null)

this.head = undefined;

2、如果head是undefined或者是unll,就意味着在向链表中添加第一个元素。

3、因此要做的就是:让head元素指向node元素,下一个node元素会自动成为undefined,因为链表最后一个节点的下一个元素始终是undefined或者null

\

三、向一个不为空的链表尾部添加元素

\

1、要向尾部添加元素,首先需要找到最后一个元素

我们只有第一个元素的引用,因此需要循环访问列表,直到找到最后一项。

current = this.head;
while (current.next != null) {
  current = current.next;
}

在循环访问链表的过程中,当current.next元素为undefined或者是null的时候,我们就知道已经到达链表尾部了,然后就让当前元素的next指针指向想要添加到链表的节点

removeAt

removeAt (index) {
  if (index >= 0 && index < this.count) {
    let current = this.head;
    if (index == 0) {
      /**
         * 这一步就是将head变成了undefined
         */
      this.head = current.next;
    } else {
      /**
         * 这一步就是将当前项的上一步和下一步连接在一起
         */
      let previous;
      for (let i = 0; i < index; i++) {
        previous = current;
        current = current.next;
      }
      previous.next = current.next;
    }
    this.count--;
    return current.element
  }
  return undefined
}

一、验证index的值是否有效,如果不是有效的,就返回undefined,也就是没有从列表中返回移除的元素

if (index >= 0 && index < this.count) {

}
return undefined

二、从链表中移除第一个元素

如果要移除第一个元素,要做的就是让head指向列表中的第二个元素

可以使用current变量来创建一个对链表中第一个元素的引用

再将current.next赋值给head,就会移除第一个元素,因为current.next是undefined

let current = this.head;
if (index == 0) {
  /**
  * 这一步就是将head变成了undefined
  */
  this.head = current.next;
}

三、移除链表的最后一个元素或者中间某个元素

\

1、需要迭代链表的节点,直到到达目标位置

for (let i = 0; i < index; i++) {

}

2、命名一个previous变量,这个变量储存current变量的前一项

let previous;
for (let i = 0; i < index; i++) {
  previous = current;
  ...
}

3、current总是不断地往后移动,移动到index的位置停止移动

let previous;
for (let i = 0; i < index; i++) {
  previous = current;
  current = current.next;
}

4、移除元素的时候,要做的就是将当前项的前一项和后面一项连接起来就行

previous.next = current.next;

这样当前项就会被丢弃了,计算器会自动回收

indexOf:查找元素在链表中的位置

indexOf (element) {
  let current = this.head;
  for (let i = 0; i < this.count && current != null; i++) {
    if (this.equalsFn(element, current.element)) {
      return i;
    }
    current = current.next;
  }
  return -1
}

1、设置一个变量来存储第一个元素的引用

2、然后迭代元素,从head开始,直到链表长度为止

3、每次迭代的时候,都去验证current节点的元素和目标元素是否相等

image.png