Estructura de datos JavaScript de Angry Liver - Lista doblemente enlazada

¡Acostúmbrate a escribir juntos! Este es el día 12 de mi participación en el "Nuevo plan diario de Nuggets · Desafío de actualización de abril", haga clic para ver los detalles del evento .

Hola a todos, mi nombre es Yang Chenggong.

En los primeros dos artículos, presentamos la lista enlazada en detalle.Sabemos que la lista enlazada es una colección ordenada cuyos elementos son independientes entre sí pero están conectados entre sí. Cuando consultamos un elemento, debemos comenzar desde el encabezado y buscar hacia atrás nivel por nivel.

La lista doblemente enlazada en realidad se basa en la lista enlazada, agregando una función de consulta "de atrás hacia adelante". Porque la lista vinculada solo se puede verificar desde el encabezado y se ha verificado al revés. La lista doblemente enlazada permite buscar desde el último elemento y continuar buscando hacia adelante.

Entonces, un elemento en una lista doblemente enlazada tiene dos referencias, una al elemento anterior y la otra al elemento siguiente.

Implementar lista doblemente enlazada

La lista doblemente enlazada es un tipo de lista enlazada, y la función básica la proporciona la lista enlazada. Por lo tanto, para implementar una lista doblemente enlazada, puede expandir directamente el método de lista enlazada original.

Usamos la forma de herencia de clases en ES6 para implementar una lista doblemente enlazada.

class doubLinkedList extend linkedList {
  constructor(whereFn) {
    super(whereFn)
    this.tail = undefined
  }
}
复制代码

El código básico anterior agrega un tailatributo , que representa la referencia del elemento al final. La función del supermétodo es llamar al constructor de linkedList para lograr una herencia completa.

El constructor se puede modificar de esta manera, y en el elemento de la lista enlazada, se debe agregar un prevatributo para que apunte al elemento anterior, por lo que se usa el mismo método de herencia para implementar:

class doubNode extend Node {
  constructor(value) {
    super(value)
    this.prev = undefined
  }
}
复制代码

Veamos cómo agregar y eliminar elementos de una lista doblemente enlazada.

Método de inserción de actualización

El método de inserción de la lista enlazada solo necesita agregar una siguiente referencia al nuevo elemento, mientras que la lista doblemente enlazada necesita proporcionar una prevreferencia . Realizamos una actualización basada en el método de inserción de la lista enlazada.

insert(item, index) {
  if(index >= 0 && index <= this.count) {
    let node = new doubNode(item)
    let current = this.head;
    if(index == 0) {
      // 1. 首位添加逻辑
      if(!this.head) {
        this.head = node
        this.tail = node
      } else {
        node.next = current
        current.prev = node
        this.head = node
      }
    } else if(index === this.count) {
      // 2. 末尾添加逻辑
      current = this.tail
      current.next = node
      node.prev = current
      this.tail = node
    } else {
      // 3. 中间位置添加逻辑
      let previous = this.getItemAt(index - 1)
      current = previous.next
      previous.next = node
      node.prev = previous
      node.next = current
      current.prev = node
    }
    this.count++;
    return true;
  }
  return false;
}
复制代码

Para ilustrar, la currentvariable representa el elemento en la posición de índice.

La parte comentada en el código es la parte a transformar, son tres partes en total, hablemos de ellas una por una.

añadido por primera vez

首位添加就是添加第一个元素,这个时候要分情况。如果是空链表,那么将 headtail 属性赋值为新元素即可。因为新元素既是表头也是表尾。

如果链表不为空,则说明表头表尾已存在,我们要新元素的 next 赋值为表头,再将表头的 prev 赋值为新元素,最后再将新元素设置为新的表头即可。

末尾添加

末尾添加主要改变的是 tail 属性。首先要将表尾的 next 赋值为新元素,然后将新元素的 prev 再指向表尾,最后将新元素赋值为新的表尾。

中间位置添加

中间位置添加是指,插入的位置不是第一个,也不是最后一个。这种情况下意味着表头和表尾都不需要动,只要将新元素与前后元素关联即可。

首先,获取索引位置的前一个元素 previous;然后再拿到索引位置的元素 current,也就是 previous.next。接下来将新元素放到它们两之间。

方法就是逐个设置 prev 和 next 属性。

升级 removeAt 方法

removeAt 方法与上面的 insert 方法改造原则一致,功能不变,只需要将删除对象前后的元素对应的 prev 和 next 属性修改,并且涉及到表尾时修改 tail 属性即可。

removeAt(index) {
  if (index >= 0 && index < this.count) {
    let current = this.head;
    if (index === 0) {
      // 1. 首位删除逻辑
      if (!current) {
        return undefined;
      }
      this.head = current.next;
      if (this.count === 1) {
        this.tail = undefined;
      } else {
        this.head.prev = undefined;
      }
      this.head = current.next;
    } else if (index === this.count) {
      // 2. 末尾删除逻辑
      current = this.tail;
      this.tail = current.prev;
      this.tail.next = undefined;
    } else {
      // 3. 中间位置删除逻辑
      current = this.getItemAt(index);
      let previous = current.prev;
      previous.next = current.next;
      current.next.prev = previous;
    }
    this.count--;
    return current.value;
  }
  return undefined;
}
复制代码

代码中注释的部分就是要改造的部分,具体如下。

首位删除

首位删除就是删除第一个元素,这个时候要分情况。

如果是空链表,删除没有意义,直接返回 undefined;如果只有一个元素,删除后会变成空链表,所以要把 headtail 属性全都置为 undefined。如果链表长度大于 1,则只需要将表头向后挪动一位,并且将远离啊的 prev 置为 undefined 即可。

末尾删除

这个比较简单,主要改变的是 tail 属性。

Establezca el pie de página como el elemento actual current, luego mueva el pie de página un lugar hacia adelante y establezca la anterior del nuevo pie de página en indefinido.

borrar posición media

La eliminación de la posición intermedia no necesita considerar la situación del encabezado y pie de página. getItemAtObtenga el elemento en la posición del índice directamente a través del método de clase y luego current.prevobtenga el elemento anterior a través de .

En este momento, cambie el siguiente atributo del elemento anterior y el atributo anterior del siguiente elemento, y omita el elemento en la posición de índice actual.

Usar lista doblemente enlazada

Experimentemos con los dos métodos escritos arriba:

var doublinked = new doubLinkedList()
doublinked.insert('北京', 0)
doublinked.insert('上海', 1)
doublinked.insert('成都', 2)
console.log(doublinked.toString()) // 北京,上海,成都
复制代码

Está bien verlo de esta manera, luego obtén el elemento del medio:

let node = doublinked.getItemAt(1)
console.log(node.prev.value) // 北京
console.log(node.next.value) // 成都
复制代码

Los resultados de la prueba son correctos, ¡y listo!

Resumir

Este artículo presenta el concepto de lista doblemente enlazada y luego utiliza la herencia de clase para implementar los dos métodos insertde lista doblemente enlazada sobre la base de la clase de lista enlazada .removeAt

Aunque solo se han escrito dos métodos, otros métodos se modifican de la misma manera que estos dos métodos, excepto que tailno prevhay diferencia entre las operaciones de lista enlazada y las operaciones de elementos de lista enlazada.

La fuente de este artículo es la cuenta oficial: Programmer Success . Esta es la undécima parte del aprendizaje de estructuras de datos y algoritmos de JavaScript. Esta serie se actualizará durante un mes. Bienvenido a seguir la cuenta oficial y haga clic en " Agregar grupo " para unirse a nuestro equipo de aprendizaje ~

Supongo que te gusta

Origin juejin.im/post/7086118078420877343
Recomendado
Clasificación