Рубрики
Без рубрики

Создание связанного списка в JavaScript

В условиях Layman связанный список представляет собой список узлов, где каждый узел удерживает две вещи: значение и указатель на следующий узел в списке. Давайте посмотрим, как мы можем реализовать один с помощью JavaScript. Теги с JavaScript, структурами данных.

Сегодня мы собираемся реализовать (отдельно) Связанный список данных Структура в JavaScript 🥳

Что такое связанный список?

В условиях Layman связанный список представляет собой список узлов, где каждый узел удерживает две вещи:

  • Ценность
  • Указатель на следующий узел в списке.

Первый узел списка называется «голова» Отказ Последний узел списка называется «хвост» Отказ

Голова и хвост не являются отдельными узлами. Они просто ссылки на первый и последний узел в списке, соответственно.

Последний узел списка указывает на null Отказ Если список пусто, то оба голова и хвостик Укажите null Отказ

Создание связанного списка в JavaScript

Чтобы определить наш связанный список данных списка, мы собираемся создать класс Отказ Мы инициализируем голова и хвост ссылки как нулевой . Мы также определяем некоторые методы ( Добавить , Prepend , Удалить С GetFirst , GetLast и Toarray ).

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

  append() {}

  prepend() {}

  delete() {}

  getFirst() {}

  getLast() {}

  toArray() {}
}

Присоединиться к

Добавляет узел до конца списка.

Мы создаем новый объект узла с 2 свойствами:

  • А ценность Имущество, содержащее предоставленную стоимость.
  • А Следующий Свойство, указывая на следующий узел, который в этом случае является null , так как мы добавляем (это последний узел в списке).

Затем мы проверяем, есть ли хвост Узел и обновите его, чтобы указать на недавно добавленную. Мы реализуем Если Проверьте, потому что в случае пустого списка (при добавлении первого узла), то хвост есть и должно быть нулевой Поскольку следующий узел нет следующего узла.

После этого мы Установите вновь добавленный узел как хвост Отказ

Наконец, мы проверяем, если голова Ссылка нулевой , который он должен сначала создавать список и Установите вновь добавленный узел как голова .

И там у вас есть, метод добавления новых узлов на наш связанный список данных списка!

append(value) {
    // New node object
    const newNode = {
        value,
        next: null
    };

    // Updating the previous tail node (last node) to point to the newly appended node
    if (this.tail) {
        this.tail.next = newNode;
    }

    // Setting the newly appended node as tail
    this.tail = newNode;

    // Setting the newly appended node as head, only if there is no head
    if (!this.head) {
        this.head = newNode;
    }
}

Предшествовать

Добавьте узел к началу списка.

Этот метод, как и предыдущий, собирается принять ценность для добавления. Реализация проста:

Мы создаем новый объект узла с предоставленным значением, но вместо настройки Следующий недвижимость в null как в Добавить Метод, Мы устанавливаем его, чтобы указать на текущий первый узел ( Глава ).

Тогда мы Установите новый узел как голова , так как он сейчас сидит в начале нашего списка и, наконец, мы проверяем, указывает ли хвост на нулевой Как мы сделали раньше, так что мы Установите его, чтобы указать на новый узел (В случае, если мы используем PROTEND, чтобы добавить узел в пустой список).

prepend(value) {
    // New node object, with pointing to the current head
    const newNode = {
      value,
      next: this.head,
    };

    // Setting the newly prepended node as head
    this.head = newNode;

    // Setting the newly appended node as tail, only if there is no tail
    if (!this.tail) {
      this.tail = newNode;
    }
  }

Довольно простой, верно? Давайте теперь посмотрим на то, как мы могли бы реализовать Удалить метод.

Удалить

Удаляет все узлы с определенным значением

Это будет тад более сложный. Но оставайся со мной, когда вы владеете основной логикой, вы собираетесь добиться более глубокого понимания на том, насколько связаны списки:)

Логика следующая:

  • Если нет голова просто верните null , так как список пуст.
  • Создайте текущий ссылку узла, инициализированной с голова узел.
  • Структура через все узлы в списке найдите те, которые содержат определенное значение и «Удалить» их, указывая свой предыдущий индекс узла на следующий узел , нравится:
  • В конце каждой петли увеличивайте текущий узел ссылки, установив его к следующему.
  • Специальная обработка для голова и хвост Узел удаления, как обсуждалось ниже.

Сначала мы собираемся обрабатывать два случая: пустой список и голова Удаление. Мы удаляем голова Узел, просто установив следующий узел как голова .

ЗАМЕТКА: А в то время как Цикл используется, потому что нам нужно найти и удалять все элементы, содержащие определенное значение, а не только первое представление. В случае, если мы удалим голова и новый голова Также квалифицируется для удаления, мы также должны удалить это тоже. То же самое, конечно, применяется для каждого последовательного узла, поэтому A в то время как петля помогает нам с этим.

delete(value) {
    // If head is missing, the list is empty, therefore return null
    if (!this.head) {
      return null;
    }

    // Update head, by setting current head value to the next node
    while (this.head && this.head.value === value) {
      this.head.next;
    }
}

Логика Nelection Core следующая:

  • Петля через все узлы до тех пор, пока их Следующий Недвижимость не null (Что произойдет, когда мы пересекаем хвост ).
  • Если следующий узел квалифицируется для удаления, Установите текущий узел, чтобы указать на узел после следующего узла.
  • В любом другом случае просто увеличивайте текущий узел, просто переназнавая его на следующий узел.
// Initializing currentNode reference as current head
let currentNode = this.head;

// Loop through every node that points to another one
while (currentNode.next) {
  // Checking whether next node's value qualifies for deletion
  if (currentNode.next.value === value) {
    // Set current node's next property to next node's next property,
    // effectively leaving no node pointing to the next node (node in the 'middle')
    currentNode.next = currentNode.next.next;
  }

  // If node doesn't qualify for deletion, set current node to the next one
  else {
    currentNode = currentNode.next;
  }
}

Наконец обрабатывать хвост Узел Удаление, как это:

// Update tail, by setting current tail value to the last non-deleted node
if (this.tail.value === value) {
  this.tail = currentNode;
}

Наш код удаления теперь должен выглядеть так:

delete(value) {
    // If head is missing, the list is empty, therefore return null
    if (!this.head) {
      return null;
    }

    // Update head, by setting current head value to the next node
    while (this.head && this.head.value === value) {
      this.head.next;
    }

    // Initializing currentNode reference as current head
    let currentNode = this.head;

    // Loop through every node that points to another one
    while (currentNode.next) {
      // Checking whether next node's value qualifies for deletion
      if (currentNode.next.value === value) {
        // Set current node's next property to next node's next property,
        // effectively leaving no node pointing to the next node (node in the 'middle')
        currentNode.next = currentNode.next.next;
      }

      // If node doesn't qualify for deletion, set current node to the next one
      else {
        currentNode = currentNode.next;
      }
    }

    // Update tail, by setting current tail value to the last non-deleted node
    if (this.tail.value === value) {
      this.tail = currentNode;
    }
  }

Розетки

Возврат текущей головы или хвостовой узел

Эти методы тривиальные, просто возвращают текущий голова и хвост :

getFirst() {
    return this.head;
  }

getLast() {
return this.tail;
}

тормить

Преобразует список в массив

Наконец, этот метод собирается преобразовать наш список на Массив для целей визуализации 😎

Мы по сути собираемся подтолкнуть каждый узел Объект к Массив и вернуть его. Я надеюсь, что код самостоятельно объясняет:

toArray() {
    const elements = [];
    let currentNode = this.head;

    while (currentNode) {
      elements.push(currentNode);
      currentNode = currentNode.next;
    }

    return elements;
}

Окончательный код

Это наш последний LinkedList класс :

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

  append(value) {
    // New node object
    const newNode = {
      value,
      next: null
    };

    // Updating the previous tail node (last node) to point to the newly appended node
    if (this.tail) {
      this.tail.next = newNode;
    }

    // Setting the newly appended node as tail
    this.tail = newNode;

    // Setting the newly appended node as head, only if there is no head
    if (!this.head) {
      this.head = newNode;
    }
  }

  prepend(value) {
    // New node object, with pointing to the current head
    const newNode = {
      value,
      next: this.head
    };

    // Setting the newly prepended node as head
    this.head = newNode;

    // Setting the newly appended node as tail, only if there is no tail
    if (!this.tail) {
      this.tail = newNode;
    }
  }

  delete(value) {
    // If head is missing, the list is empty, therefore return null
    if (!this.head) {
      return null;
    }

    // Update head, by setting current head value to the next node
    while (this.head && this.head.value === value) {
      this.head.next;
    }

    // Initializing currentNode reference as current head
    let currentNode = this.head;

    // Loop through every node that points to another one
    while (currentNode.next) {
      // Checking whether next node's value qualifies for deletion
      if (currentNode.next.value === value) {
        // Set current node's next property to next node's next property,
        // effectively leaving no node pointing to the next node (node in the 'middle')
        currentNode.next = currentNode.next.next;
      }

      // If node doesn't qualify for deletion, set current node to the next one
      else {
        currentNode = currentNode.next;
      }
    }

    // Update tail, by setting current tail value to the last non-deleted node
    if (this.tail.value === value) {
      this.tail = currentNode;
    }
  }

  getFirst() {
    return this.head;
  }

  getLast() {
    return this.tail;
  }

  toArray() {
    const elements = [];
    let currentNode = this.head;

    while (currentNode) {
      elements.push(currentNode);
      currentNode = currentNode.next;
    }

    return elements;
  }
}

Связанный список против массива

Плюс

  • При использовании связанного списка нет необходимости заранее указывать его длину, что является случай при работе с массивами. Это происходит, потому что массивы нуждаются в непрерывной области выделенной памяти, тогда как связанные списки не страдают от этого ограничения, просто потому, что они используют указатели к определению своих узлов.

ЗАМЕТКА: Однако JavaScript и большинство современных языков программирования реализуют абстрактный тип данных, называемый «динамические массивы». По сути, они автоматически автоматически изменяются массивы, которые позволяют нам эффективно использовать их во время записи кода на более высоком уровне. Под капотом основанный в основе JavaScript Engine создает «реальный» массив, который обычно увеличивается в размере и вмещает все наши ценности. Когда он полностью получен, создается новый, и все старые элементы копируются над ним.

  • Другой случай использования, когда связанные списки сияют, когда мы часто добавляем новые элементы в начале или в любом месте, за исключением его конца. При использовании массивов вы должны сдвинуть все элементы вправо, чтобы предписать или информировать новый, поэтому тратить множество вычислений При использовании связанного списка вам просто нужно изменить указатель предыдущего узла, чтобы указать на новый узел.

Господин

  • Доступ к элементам в LL представляет собой o (n) сложности времени (линейных), тогда как доступ к элементам в массиве составляет O (1) сложности времени (константы), при условии, что мы знаем индекс элемента, который мы пытаемся получить доступ, конечно. Это происходит потому, что в случае, если мы должны пройти каждый узел, пока мы не найдем тот, который мы ищем.

Спасибо за чтение, надеюсь, я был достаточно ясен. Не стесняйтесь предоставлять отзыв на случай, если я что-то пропустил! 😊

Оригинал: “https://dev.to/mliakos/creating-a-linked-list-in-javascript-dgh”