Eliminar un nodo en una lista vinculada en C++

Jinku Hu 12 octubre 2023
Eliminar un nodo en una lista vinculada en C++

Este artículo discutirá el método de cómo implementar una función que elimina un nodo dado en una lista enlazada C++.

Implementar una función para eliminar un nodo dado en una lista vinculada

En este artículo, implementamos una lista enlazada individualmente desde cero sin utilizar los contenedores de STL. Por lo tanto, necesitamos definir algunas funciones necesarias para administrar los nodos en una lista vinculada.

El elemento insertNode es la función principal que debe invocarse para crear una nueva lista vinculada. Como necesitamos almacenar el encabezado de la lista, el insertNode devuelve el puntero al nodo de tipo ListNode. Esta última es la representación mínima del nodo de la lista enlazada. Solo contiene un puntero al siguiente nodo y al objeto de datos string.

Durante la prueba y demostración del programa, es importante tener algunas funciones de utilidad para mostrar algunos mensajes en la consola del usuario. En este caso, el elemento printNodes se utiliza para imprimir todos los nodos en la estructura de lista dada. Además, necesitamos desasignar cada nodo existente en la lista al salir del programa usando la función freeNodes al asignar nuevos nodos en la memoria dinámica.

Una vez que construimos una lista con los datos arbitrarios como se muestra en la función main del siguiente fragmento de código, estamos listos para invocar deleteNode, que implementa la operación de eliminación de nodos. La eliminación de un nodo requiere que se manejen varios casos de esquina en él. Es decir, el escenario en el que el nodo dado es el mismo que el encabezado de la lista y el otro cuando el nodo dado es el único nodo en la lista.

En el último escenario, podemos simplemente llamar al operador remove en el puntero del nodo y regresar de la función. Aunque es importante asignar nullptr a la dirección porque esto nos ayudará a agregar nuevos elementos a la misma variable head en la función principal.

Por otro lado, eliminar el nodo principal cuando hay otros nodos en la lista es relativamente complicado. Tenemos que copiar el contenido del segundo nodo al nodo principal y eliminar el anterior. Observe que cada caso devuelve el valor EXIT_SUCCESS para indicar una llamada de función exitosa.

#include <iostream>
#include <string>

using std::cin;
using std::cout;
using std::endl;
using std::string;

struct ListNode {
  struct ListNode *next{};
  string data;
};

struct ListNode *insertNode(struct ListNode *root, string data) {
  auto new_node = new ListNode;
  if (root) {
    while (root->next) root = root->next;

    new_node->next = nullptr;
    new_node->data = std::move(data);
    root->next = new_node;

    return root->next;
  }
  new_node->next = nullptr;
  new_node->data = std::move(data);
  return new_node;
}

int deleteNode(struct ListNode *root, struct ListNode *node) {
  if (node == nullptr || root == nullptr) return EXIT_FAILURE;

  if (root == node) {
    if (root->next == nullptr) {
      delete node;
      root = nullptr;
      return EXIT_SUCCESS;
    }

    node = root->next;
    root->data = root->next->data;
    root->next = root->next->next;
    delete node;
    return EXIT_SUCCESS;
  }

  auto prev = root;
  while (prev->next != node && prev->next != nullptr) {
    prev = prev->next;
  }

  prev->next = node->next;
  delete node;
  return EXIT_SUCCESS;
}

void freeNodes(struct ListNode *root) {
  struct ListNode *tmp = nullptr;
  while (root) {
    tmp = root;
    root = root->next;
    delete tmp;
  }
}

void printNodes(struct ListNode *node) {
  auto count = 0;
  while (node) {
    cout << "node " << count << " - data: " << node->data << endl;
    node = node->next;
    count++;
  }
}

int main() {
  struct ListNode *head = nullptr;

  head = insertNode(head, "Xenial");

  insertNode(head, "Artful");
  printNodes(head);
  cout << " ----------------------------------- " << endl;

  deleteNode(head, head);
  printNodes(head);

  freeNodes(head);
  return EXIT_SUCCESS;
}

Producción :

node 0 - data: Xenial
node 1 - data: Artful
 -----------------------------------
node 0 - data: Artful

El código de función restante implementa el caso normal, donde el nodo dado se desengancha de la cadena de lista y luego se desasigna usando el operador delete. Sin embargo, tenga en cuenta que esta operación requiere que se encuentre el nodo anterior, que es la operación de tiempo lineal para cada nodo excepto el del encabezado de la lista. Por lo general, se debe almacenar el final de la lista en la estructura de la lista vinculada para garantizar la eliminación de tiempo constante para el final de la lista.

El siguiente fragmento de código muestra un escenario de función main diferente, donde un nodo se elimina del medio de la lista.

#include <iostream>
#include <string>

using std::cin;
using std::cout;
using std::endl;
using std::string;

struct ListNode {
  struct ListNode *next{};
  string data;
};

struct ListNode *insertNode(struct ListNode *root, string data) {
  auto new_node = new ListNode;
  if (root) {
    while (root->next) root = root->next;

    new_node->next = nullptr;
    new_node->data = std::move(data);
    root->next = new_node;

    return root->next;
  }
  new_node->next = nullptr;
  new_node->data = std::move(data);
  return new_node;
}

int deleteNode(struct ListNode *root, struct ListNode *node) {
  if (node == nullptr || root == nullptr) return EXIT_FAILURE;

  if (root == node) {
    if (root->next == nullptr) {
      delete node;
      root = nullptr;
      return EXIT_SUCCESS;
    }

    node = root->next;
    root->data = root->next->data;
    root->next = root->next->next;
    delete node;
    return EXIT_SUCCESS;
  }

  auto prev = root;
  while (prev->next != node && prev->next != nullptr) {
    prev = prev->next;
  }

  prev->next = node->next;
  delete node;
  return EXIT_SUCCESS;
}

void freeNodes(struct ListNode *root) {
  struct ListNode *tmp = nullptr;
  while (root) {
    tmp = root;
    root = root->next;
    delete tmp;
  }
}

void printNodes(struct ListNode *node) {
  auto count = 0;
  while (node) {
    cout << "node " << count << " - data: " << node->data << endl;
    node = node->next;
    count++;
  }
}

int main() {
  struct ListNode *head = nullptr;

  head = insertNode(head, "Xenial");

  auto iter = insertNode(head, "Bionic");
  insertNode(head, "Artful");
  printNodes(head);
  cout << " ----------------------------------- " << endl;

  deleteNode(head, iter);
  printNodes(head);

  freeNodes(head);
  return EXIT_SUCCESS;
}

Producción :

node 0 - data: Xenial
node 1 - data: Bionic
node 2 - data: Artful
 -----------------------------------
node 0 - data: Xenial
node 1 - data: Artful
Autor: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook

Artículo relacionado - C++ Data Structure