Estructura de datos JavaScript de Angry Liver - Lista vinculada (1)

¡Acostúmbrate a escribir juntos! Este es el décimo día de mi participación en el "Nuggets Daily New Plan · April Update Challenge", haz clic para ver los detalles del evento .

Hola a todos, mi nombre es Yang Chenggong.

En los artículos anteriores, hemos aprendido estructuras de datos como matrices, pilas, colas y colas de dos extremos. Hoy nos encontramos con un nuevo amigo, una estructura de datos dinámica: una lista enlazada.

¿Qué es una lista enlazada?

Una lista enlazada es un conjunto dinámico de colecciones ordenadas. ¿Cómo entender la "dinámica" aquí?

Primero recuerde la matriz que aprendimos anteriormente, es la estructura de datos más básica y tiene un tamaño fijo en la mayoría de los idiomas. La lista vinculada se basa en la matriz, lo que permite agregar y eliminar elementos a voluntad, lo que equivale a una matriz "dinámica".

En este punto, puede preguntar: las matrices en JavaScript también son dinámicas y puede agregar y eliminar elementos a voluntad. Esto es cierto, pero los métodos nativos proporcionados por JavaScript, si bien son cómodos de usar, tienen un bajo rendimiento.

¿Por qué? Supongamos que desea insertar un elemento al principio o en el medio de la matriz, luego, comenzando desde esta posición, todos los elementos siguientes deben desplazarse hacia atrás un lugar. En este momento, no es tan simple como agregar un elemento, sino en esencia, se modifican todos los siguientes elementos.

Cuando la matriz es muy grande, cuanto antes se agrega la posición, más elementos se deben "mover". Por lo tanto, cuanto mayor sea la matriz, menor será el rendimiento de la manipulación de los elementos de la matriz.

Pero las listas enlazadas son diferentes. Aunque una lista enlazada tiene la misma función que una matriz, los elementos de la lista enlazada se colocan de forma independiente en la memoria y no son continuos. Cada elemento consiste en el valor del propio elemento y una referencia al siguiente elemento.El diagrama de estructura es el siguiente:

imagen.png

Es más claro ver esta imagen. Cuando necesite agregar un elemento en cualquier posición, solo necesita agregar un elemento, modificar la referencia del elemento actual y el elemento anterior, y los otros elementos no cambiarán. Entonces, independientemente de la longitud de su lista vinculada, el rendimiento de la manipulación de elementos es muy alto.

¿Pero las listas enlazadas deben ser mejores que las matrices? Ninguno. En la matriz, podemos acceder a los elementos en cualquier posición por índice, y debido a que cada elemento de la lista enlazada es independiente entre sí, si queremos encontrar un elemento, debemos comenzar desde el primer elemento ( el encabezado ) y buscar hacia abajo. uno por uno hasta encontrar el objetivo.

implementar una lista enlazada

Presentamos la lista vinculada anterior y la comparamos con la matriz, describiendo brevemente las diferencias, ventajas y desventajas de los dos. Ahora que entendemos esto, podemos comenzar a implementar una lista enlazada.

首先看一下基本结构:

class linkedList {
  constructor() {
    this.count = 0;
    this.head = undefined;
  }
}
复制代码

上述代码有两个属性:

  • count:表示链表的长度,也就是元素的个数
  • head:存储第一个元素(表头)的引用

前面说过,链表的元素包含自身的值和下一个元素的引用。我们在添加元素时,需要一个快捷的创建链表元素的方式,因此写一个 Node 类表示链表的元素:

class Node {
  constructor(value) {
    this.value = value;
    this.next = undefined;
  }
}
复制代码

有了这两个类,接下来就可以编写操作链表元素的方法了。

本篇只介绍常用的两个方法:

  • push:向链表尾部添加一个元素
  • removeAt:从链表某处移除一个元素

push 实现

向链表尾部添加元素时,可能有两种情况:

  • 链表为空,则添加第一个元素
  • 链表不为空,在所有元素之后添加元素
push(item) {
  let node = new Node(item)
  let current;
  if(!this.head) {
    this.head = node
  } else {
    current = this.head
    while(current.next) {
      current = current.next
    }
    current.next = node;
  }
  this.count++;
}
复制代码

代码中首先判断存储表头引用的变量 head 是否赋值。如果未赋值则表示链表没有元素,此时将 head 赋值为新创建的元素即可。

如果变量 head 已赋值,则表示链表中已经有元素。我们通过 head.next 一层一层向下找,直到找到最后一个元素,即 next 属性为 undefined 的元素。

此时将链表最后一个元素的 next 属性赋值为新元素,就完成了尾部添加。

最后,不要忘了将长度 count 属性自增一。

removeAt 实现

上面我们实现了添加元素的方法,这里再说如何从某处移除元素。

从某处删除元素,类似于删除数组中某个下标的元素。removeAt 方法要提供一个数值类型的参数,相当于数组的索引,表示要删除这个位置的元素。

基础结构如下:

removeAt(index) {
  if(index >= 0 && index < this.count) {
    // 具体逻辑
  }
  return undefined;
}
复制代码

在这个方法中,首先要限制参数 index 在 0 和 链表长度之间,然后再分两种情况去删除元素。

如果 index 等于 0,那么操作就比较简单,只需要将 head 属性的指向后移一位即可。

对应到代码是这样的:

if(index == 0) {
  let current = this.head;
  this.head = current.next;
}
复制代码

如果 index 大于 0,那么总体的思路分三步:

  1. 找到 index 对应的元素 B
  2. 找到 B 的上一个元素 A
  3. apuntará A.nextaB.next

Cuando vas a la tercera parte, es equivalente a pasar por alto el enlace con B directamente, lo que significa que el elemento B se elimina.

El código correspondiente es este:

if(index > 0) {
  let current = this.head;
  let previous; 
  for(let i = 0; i < index; i++) { 
    previous = current; 
    current = current.next; 
  }
}
复制代码

Combinando los dos casos, el código completo es el siguiente:

removeAt(index) {
  if(index >= 0 && index < this.count) {
    let current = this.head;
    // 第一项
    if(index == 0) {
      this.head = current.next;
    } else {
      let previous;
      for(let i = 0; i < index; i++) {
        previous = current;
        current = current.next;
      }
    }
    this.count--;
    return current.value
  }
  return undefined;
}
复制代码

Resumir

Este artículo presenta el concepto de lista enlazada y cómo se diferencia de la matriz, pushy removeAtdos métodos.

El contenido de la lista enlazada es relativamente complejo. Puede comprender los dos métodos presentados en este artículo. En el próximo artículo, agregaremos otros métodos y haremos la prueba del resultado final.

La fuente de este artículo es la cuenta oficial: Programmer Success . Esta es la novena parte del aprendizaje de algoritmos y estructuras de datos 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/7085374698971742221
Recomendado
Clasificación