Las listas vinculadas, enlazadas o enhebradas en la estructuras de datos lineales en las que los elementos no se almacenan en ubicaciones contiguas en la memoria y en las que los elementos están vinculados entre sí mediante punteros. La siguiente figura muestra la estructura de listas enlazadas:

Las listas de subprocesos constan de nodos y cada nodo contiene un campo de datos y un puntero (enlace) al siguiente nodo de la lista.
Tabla de contenidos
- ¿Por qué utilizar listas vinculadas?
- Listas y matrices vinculadas
- Desventajas de las listas enlazadas
- Representación de listas enlazadas
- Crea listas enlazadas
- Navegación por los nodos en las listas de los subprocesos
- Agregar nodos a listas de subprocesos
- Eliminar nodos de listas vinculadas
- Buscar un elemento en la lista encadenada
- Fuente
¿Por qué utilizar listas vinculadas?
Las matrices se pueden utilizar para almacenar datos lineales del mismo tipo, pero el uso de estas matrices tienen las siguientes desventajas:
- Las matrices tienen un tamaño fijo, lo que significa que debemos conocer el número máximo de elementos que entrarán en la matriz de antemano, y la cantidad de memoria reservada es igual a la cantidad máxima de elementos en la matriz, independientemente de cuantos elementos la componen realmente.
- Para agregar un nuevo elemento a la matriz requiere un elevado consumo de memoria. Esto se debe a que agregar un nuevo elemento significa encontrar un espacio para él en la matriz, lo que a su vez significa desplazar los elementos de la matriz de sus posiciones.
Supongamos el siguiente ejemplo, digamos que tenemos una lista de identificadores dispuestos en una matriz: id[] = [10, 12, 15, 20, 22]
.
Si queremos agregar un nuevo identificador que contenga el valor 15
sin alterar el orden de los elementos, entonces tenemos que mover todos los elementos que siguen al identificador 10
.
El proceso de eliminación también es costoso, a menos que usemos algunas técnicas especiales. Por ejemplo, para poder borrar el identificador 12
en el arreglo anterior, debemos mover todos los elementos que siguen al identificador 12
.
Listas y matrices vinculadas
Las listas enlazadas difieren de las matrices en los siguientes puntos:
- Una matriz es una estructura de datos que contiene un grupo de elementos de tipo similar, mientras que una lista vinculada es una estructura de datos no primitiva que contiene un grupo de elementos relacionados y desordenados llamados nodos.
- Los elementos de las matrices pertenecen a índices, lo que significa que para acceder al cuarto elemento de la matriz, el nombre de la variable debe escribirse con su índice o ubicación entre corchetes.
- En las listas enlazadas, debes empezar desde la cabecera y luego ir pasando por los elementos uno por uno hasta llegar al cuarto elemento.
- Se puede acceder rápidamente a un elemento de una matriz. Para una lista vinculada, se necesita más tiempo lineal para acceder a los elementos. Por lo tanto, las listas de subprocesos son un poco más lentas que las matrices.
- Las operaciones como la adición y eliminación toman mucho tiempo en matrices, pero son rápidas en listas de subprocesos.
- Las matrices tienen un tamaño fijo, a diferencia de las listas de subprocesos que tienen un tamaño variable y son flexibles y tienen la capacidad de aumentar o disminuir su tamaño según sea necesario.
- La información sobre el uso de matrices se asigna a la memoria en el momento de la compilación. Cuando se utilizan listas de subprocesos, la memoria se reserva en el tiempo de ejecución.
- Los elementos de la matriz se almacenan en orden y se almacenan en listas relacionadas aleatoriamente.
- Las matrices requieren menos memoria porque los datos reales se almacenan en el índice y las listas de subprocesos requieren más memoria porque necesitan almacenar elementos adicionales para apuntar a los nodos anteriores y posteriores.
- La memoria no se puede utilizar de forma eficiente con matrices, a diferencia de las listas enlazadas.
Desventajas de las listas enlazadas
- No se puede acceder a las listas de subprocesos de forma aleatoria, se debe acceder a ellas en orden comenzando desde el primer nodo. Por lo tanto, la búsqueda binaria no se puede realizar de manera eficiente si usamos el método predeterminado para tratar con listas enhebradas.
- Cada elemento necesita espacio de memoria adicional para que cada elemento esté asociado con un puntero.
- No es compatible con la caché. Dado que los elementos de la matriz están en ubicaciones contiguas, las referencias a los elementos están en una única localidad de referencia, algo que falta en las listas vinculadas.
Representación de listas enlazadas
Una lista de subprocesos está representada por un puntero al primer nodo en la lista de subprocesos. El primer nodo se llama cabeza, y si la lista de subprocesos está vacía, el valor del encabezado es NULL.
Cada nodo de la lista tiene dos partes:
- datos.
- Punteros o referencia al siguiente nodo.
Los nodos se pueden representar en C usando estructuras. El siguiente ejemplo muestra un nodo de lista enhebrado con datos escalares.
struct Node { int data; struct Node *next; }
En Java y C #, las listas de subprocesos se pueden representar por una clase y los nodos por una clase separada, y la clase de lista de subprocesos contiene una referencia a la clase de nodo.
class LinkedList { Node head; class Node { int data; Node next; // constructor para crear un nuevo nodo Node (int d) {data = d;} } }
class LinkedList { Node head; class Node { int data; Node next; // constructor para crear un nuevo nodo // el valor del nodo siguiente se inicializa automáticamente a nulo Node(int d) {data = d;} } }
# Node class class Node: #función para inicializar el objeto de nodo def __init__(self, data): self.data = data # Asignamos datos self.next = None # Inicializa el siguiente nodo para que esté vacío null # class LinkedList: # Función para inicializar el objeto de lista enhebrada def __init__(self): self.head = None
Crea listas enlazadas
Los siguientes ejemplos muestran cómo crear listas de subprocesos en varios lenguajes de programación(C++, Python, Java) :
#include <bits/stdc++.h> using namespace std; class Node { public: int data; Node *next; } // Este programa crea una lista sencilla // que tiene tres nodos int main() { Node* head = NULL; Node* second = NULL; Node* third = NULL; // reservar posiciones para 3 nodos head = new Node(); second = new Node(); third = new Node(); /* Tres bloques se reservan en memoria dinámicamente y tenemos punteros a estos bloques son head second third | | | | | | +---+-----+ +----+----+ +----+----+ | # | # | | # | # | | # | # | +---+-----+ +----+----+ +----+----+ representa cualquier valor aleatorio Los datos son aleatorios porque no hemos asignado ningún valor aún */ head->data = 1; // asigna un valor al primer head->next = second; // atar el primer nudo con el segundo /* Los datos se asignan a la parte de datos del primer bloque (encabezado del menú) y el puntero posterior apunta al segundo bloque, por lo que los dos bloques están relacionados head second third | | | | | | +---+---+ +----+----+ +-----+----+ | 1 | o----->| # | # | | # | # | +---+---+ +----+----+ +-----+----+ */ second->data = 2; // asigna un valor al segundo nodo second->next = third; // conecta el segundo nodo al tercer /* Asignar un valor a la parte de datos del segundo bloque, y el puntero al segundo bloque apunta al tercer bloque, por lo que los dos bloques están vinculados head second third | | | | | | +---+---+ +---+---+ +----+----+ | 1 | o----->| 2 | o-----> | # | # | +---+---+ +---+---+ +----+----+ */ third->data = 3; // asigna un valor al tercer nodo third->next = NULL; /* Asignar un valor a la parte de datos del tercer nodo Null y el puntero final en el tercer bloque apunta al valor para indicar el final de la lista enhebrada en esa posición head | | +---+---+ +---+---+ +----+------+ | 1 | o----->| 2 | o-----> | 3 | NULL | +---+---+ +---+---+ +----+------+ Tenga en cuenta que el encabezado de la lista es suficiente para representar la lista completa. Puede navegar por todos los elementos del menú siguiendo el cursor */ return 0; }
clase Nodo: # Una función para inicializar el objeto de nodo def __init__(self, data): self.data = data # Asignar datos a self.next = None # null Inicializa el nodo subsiguiente para ser # clase de lista vinculada que contiene el objeto class LinkedList: # Inicializar encabezado de lista def __init__ ( self ): self.head = none if __name__=='__main__': # Comenzamos con una lista de subprocesos vacía llist = LinkedList() llist.head = Node(1) second = Node(2) third = Node(3) ''' Tres bloques se reservan dinámicamente en la memoria y tenemos punteros a estos bloques son first, second, third llist.head second third | | | | | | +----+------+ +----+------+ +----+------+ | 1 | None | | 2 | None | | 3 | None | +----+------+ +----+------+ +----+------+ ''' llist.head.next = second; # une el primer nudo al segundo ''' El primer nodo ahora se refiere al segundo nodo, por lo que están interconectados llist.head second third | | | | | | + ---- + ------ + + ---- + ------ + + ---- + ------ + | 1 | o --------> | 2 | nulo | 3 | | nulo | + ---- + ------ + + ---- + ------ + + ---- + ------ + ''' second.next = third; # une el segundo nudo con el tercero ''' El segundo nudo se refiere al tercer nudo, por lo que están interconectados llist.head second third | | | | | | + ---- + ------ + + ---- + ------ + + ---- + ------ + | 1 | o --------> | 2 | o --------> | 3 | nulo | + ---- + ------ + + ---- + ------ + + ---- + ------ + '''
class LinkedList { Node head; // parte superior de la lista /* lista de subprocesos nodo */ static class Node { int data; Node next; Node(int d) { data = d; next=null; } // constructor } } /* Continuar creando una lista simple de tres nodos */ public static void main(String[] args) { /* Comenzamos con una lista vacía */ LinkedList llist = new LinkedList(); llist.head = new Node(1); Node second = new Node(2); Node third = new Node(3); /* Tres nodos reservan un lugar en la memoria dinámicamente y nuestras referencias a estos bloques son first, second, third llist.head second third | | | | | | + ---- + ------ + + ---- + ------ + + ---- + ------ + | 1 | nulo | | 2 | nulo | | 3 | nulo | + ---- + ------ + + ---- + ------ + + ---- + ------ + */ llist.head.next = second; // atar el primer nudo al segundo /* El primer nodo ahora se refiere al segundo nodo y, por lo tanto, los dos nodos están vinculados llist.head second third | | | | | | + ---- + ------ + + ---- + ------ + + ---- + ------ + | 1 | o --------> | 2 | nulo | | 3 | nulo | + ---- + ------ + + ---- + ------ + + ---- + ------ + */ second.next = third; // conecta el segundo nodo al tercer nodo /* Ahora el segundo nodo se refiere al tercer nodo y así los dos nodos están vinculados llist.head second third | | | | | | + ---- + ------ + + ---- + ------ + + ---- + ------ + | 1 | o --------> | 2 | o --------> | 3 | nulo | + ---- + ------ + + ---- + ------ + + ---- + ------ + */ } }
Navegación por los nodos en las listas de los subprocesos
Los siguientes ejemplos muestran cómo navegar por los nodos en listas de subprocesos en varios lenguajes de programación (C++, Python, Java):
#include <bits/stdc++.h> using namespace std; class Node { public: int data; Node *next; }; // Esta función imprime el contenido de la lista de subprocesos // comenzando desde el nodo dado void printList(Node *n) { while (n != NULL) { cout << n->data << " "; n = n->next; } } // prueba la función anterior int main() { Node* head = NULL; Node* second = NULL; Node* third = NULL; // reserva tres nodos en la memoria head = new Node(); second = new Node(); third = new Node(); head->data = 1; // Asignar los datos a la head->next = second; // atar el primer nudo al segundo second->data = 2; // Asignar los datos al segundo nodo second->next = third; third->data = 3; // Asignar los datos al tercer nodo third->next = NULL; printList(head); return 0; }
class Node: # Una función para inicializar el objeto de nodo def __init__(self, data): self.data = data # Asignar datos self.next = None # null Inicializa el nodo subsiguiente # class una lista vinculada que contiene un objeto de nodo de class LinkedList: # Inicializar encabezado de lista def __init__(self): self.head = None # Esta función imprime el contenido de la lista # enhebrada comenzando desde el nodo dado def printList(self): temp = self.head while (temp): print temp.data, temp = temp.next if __name__=='__main__': # comenzar con una lista de subprocesos vacía llist = LinkedList() llist.head = Node(1) second = Node(2) third = Node(3) llist.head.next = second; # Conecta el primer nudo con el second.next = third; # Ate el segundo nudo con el tercero llist.printList()
class LinkedList { Node head; // parte superior de la lista /* Nodo en la lista de subprocesos */ static class Node { int data; Node next; Node(int d) { data = d; next=null; } // constructor } /* Esta función imprime el contenido de la lista enhebrada comenzando desde el encabezado de la lista */ public void printList() { Node n = head; while (n != null) { System.out.print(n.data+" "); n = n.next; } } /* Crea una lista de subprocesos de tres nodos */ public static void main(String[] args) { /* Empiece con una lista de subprocesos vacía */ LinkedList llist = new LinkedList(); llist.head = new Node(1); Node second = new Node(2); Node third = new Node(3); llist.head.next = second; // Conecta el primer nodo al second.next = third; // atar el segundo nudo al tercero llist.printList(); } }
El código anterior da la siguiente salida:
1 2 3
Agregar nodos a listas de subprocesos
Los nodos se pueden agregar a la lista vinculada en tres lugares:
- al principio de la lista enhebrada.
- después de un cierto nodo.
- al final de la lista vinculada.
Agregue un nodo al comienzo de la lista de subprocesos
El nuevo nodo siempre se agrega antes del encabezado de la lista de subprocesos, y el nuevo nodo se convierte en el encabezado de esa lista. Por ejemplo, si tenemos la lista enlazada siguiente: y 10->15->20->25
añadimos el número 5
al principio de la lista, que se verá como esto: 5->10->15->20->25
.
Si llamamos a la función que agrega el nuevo elemento al principio de la lista de subprocesos por nombre, push()
entonces esta función debe recibir un puntero al puntero del encabezado. Esto se debe a que este puntero debe apuntar al nuevo nodo.
La complejidad temporal de la función push()
O (1)
se debe a que realiza una cantidad fija de trabajo.
Agregar un nodo después de un nodo existente
En este caso, tenemos un puntero a un nodo específico y queremos agregar un nuevo nodo después.
La complejidad temporal de una función insertAfter()
O(q)
se debe a que realiza una cantidad fija de trabajo.
Agregue un nodo al final de la lista de subprocesos
El nuevo nodo siempre se agrega después del último nodo en la lista de subprocesos. Por ejemplo, si tenemos la lista enlazada siguiente: y 5->10->15->20->25
queremos añadir el elemento 30
al final de la lista, la lista enlazada se hace de la siguiente manera: 5->10->15->20->25->30
.
Dado que el encabezado suele ser una lista enhebrada, tenemos que pasar por los elementos de la lista hasta el final, y luego cambiar el nodo junto al último nodo para convertirlo en el nuevo nodo.
La cantidad de tiempo que representa la complejidad de este proceso para O(n)
representar los n
nodos de conteo en la lista vinculada, y cuando el tráfico por parte de los elementos existentes de la función de trabajo, la función para realizar el O(n)
trabajo.
Esta función se puede mejorar con complejidad O(1)
manteniendo un puntero adicional al final de la lista de subprocesos.
Ejemplos y aplicaciones en código
Los siguientes ejemplos muestran los tres métodos de suma y en varios lenguajes de programación:
#include <bits/stdc++.h> using namespace std; // lista de nodos interconectado class Node { public: int data; Node *next; }; /* Inserta un nuevo nodo al principio de la lista usando un puntero al encabezado de la lista y el entero dado */ void push(Node** head_ref, int new_data) { /* 1. Reserva la ubicación del nodo en la memoria */ Node* new_node = new Node(); /* 2. Agregar datos */ new_node->data = new_data; /* 3. Hacer que el encabezado de la lista sea el siguiente nodo del nuevo nodo */ new_node->next = (*head_ref); /* 4. Mover el encabezado de la lista para apuntar al nuevo nodo */ (*head_ref) = new_node; } /* Inserta un nodo después del nodo anterior dado */ void insertAfter(Node* prev_node, int new_data) { /* 1. Null Comprueba que el nodo anterior dado no puede ser NULL */ if (prev_node == NULL) { cout<<"the given previous node cannot be NULL"; return; } /* 2. Reserva la ubicación del nuevo nodo en la memoria */ Node* new_node = new Node(); /* 3. Agregar datos */ new_node->data = new_data; /* 4. Hacer que el siguiente nodo del nuevo nodo sea el sucesor del nodo anterior */ new_node->next = prev_node->next; /* 5. Mueva el siguiente nodo del nodo anterior para convertirse en el nuevo nodo */ prev_node->next = new_node; } /* Agrega un nuevo nodo al final de la lista usando el puntero (un puntero a un puntero) al encabezado de la lista y el entero dado */ void append(Node** head_ref, int new_data) { /* 1. Reserva la nueva ubicación del nodo en la memoria */ Node* new_node = new Node(); /* utilizado en el paso 5 */ Node *last = *head_ref; /* 2. Insertar datos */ new_node->data = new_data; /* 3. El nuevo nodo será el último nodo en la lista por lo que haremos que el siguiente nodo sea NULL */ new_node->next = NULL; /* 4. Si la lista está vacía, el nuevo nodo será en la cabecera de la lista */ if (*head_ref == NULL) { *head_ref = new_node; return; } /* 5. Si la lista no está vacía, mueva el nuevo nodo al final de la lista */ while (last->next != NULL) last = last->next; /* 6. Cambiamos el nodo final al último nodo. */ last->next = new_node; return; } // Esta función imprime el contenido de la lista de subprocesos // comenzando desde el encabezado void printList(Node *node) { while (node != NULL) { cout<<" "<<node->data; node = node->next; } } // probar las funciones anteriores int main() { /* comenzar con una lista vacía */ Node* head = NULL; // inserte el elemento 6 // la lista se verá así // 6-> NULL append(&head, 6); // inserte el elemento 7 al principio de la lista // la lista se verá así // 7-> 6-> NULL push(&head, 7); // inserte el elemento 1 al principio de la lista // la lista se verá así // 1-> 7-> 6-> NULL push(&head, 1); // inserta el elemento 4 al final de la lista append(&head, 4); // inserta el elemento 8 después del elemento 7 // la lista se verá como insertAfter(head->next, 8); cout<<"Created Linked list is: "; printList(head); return 0; }
# class node class Node: # Una función para inicializar el objeto de nodo def __init__(self, data): self.data = data # Asignar datos a self.next = None # null Inicializa el nodo subsiguiente para ser # La clase de lista vinculada incluye un objeto de nodo de class LinkedList: # Función para inicializar el encabezado de la lista def __init__(self): self.head = None # función para insertar un nodo al principio de la lista def push(self, new_data): # 1: reservando la ubicación del nodo en la memoria # 2: agregando datos new_node = Node(new_data) # 3. Haga que el nodo final del nuevo nodo sea el encabezado new_node.next = self.head # 4: Mueva el encabezado de la lista para apuntar al nuevo nodo self.head = new_node # Este método inserta un nuevo nodo después de un nodo dado def insertAfter(self, prev_node, new_data): # 1: Verifique que un nodo dado esté realmente en la lista de subprocesos if prev_node is None: print "The given previous node must inLinkedList." return # 2: Cree un nuevo nodo # 3: agregue datos new_node = Node(new_data) # 4: Haga que el nodo que sigue al nuevo nodo sea el nodo que sigue al new_node.next = prev_node.next # 5: Hacer que el nuevo nodo al nodo raíz de la dada prev_node.next = new_node # agrega un nuevo nodo al final de la lista de subprocesos def append(self, new_data): # 1: Crear un nuevo nodo # 2: Agregar datos # 3: Ninguno Hacer que el siguiente nodo sea new_node = Node(new_data) # 4: Haga que el nuevo nodo sea el encabezado de la lista # si la lista enhebrada está vacía if self.head is None: self.head = new_node return # 5: de lo contrario, Venntql a través de los elementos del menú hasta el último nodo last = self.head while (last.next): last = last.next # 6: cambiar la siguiente último nodo last.next = new_node # función auxiliar para imprimir el contenido de la lista enhebrada def printList(self): temp = self.head while (temp): print temp.data, temp = temp.next # Prueba las funciones anteriores if __name__=='__main__': # Empezamos con una lista vacía llist = LinkedList() # Insertamos el elemento 6 en la lista para que se convierta en # 6-> Ninguno llist.append(6) # Inserte el elemento 7 al principio de la lista, por lo que se convierte en # 7-> 6-> Ninguno llist.push(7); # Insertamos el elemento 1 al principio de la lista para que se convierta en # 1 -> 7-> 6-> None llist.push(1); # Ponemos el elemento 4 al final de la lista para que se convierta en # 1 -> 7-> 6-> 4-> None llist.append(4) # Insertamos el elemento 8 después del elemento 7 en la lista para que se convierta en # 1 -> 7-> 8-> 6-> 4-> None llist.insertAfter(llist.head.next, 8) print 'Created linked list is:', llist.printList()
class LinkedList { Node head; // parte superior de la lista // nodo de lista enhebrada class Node { int data; Node next; Node(int d) {data = d; next = null; } } /* Inserta un nuevo nodo en la parte superior de la lista */ public void push(int new_data) { /* 1: Reserva la ubicación del nodo en la memoria 2: Agrega información */ Node new_node = new Node(new_data); /* 3. Hacer que el encabezado de la lista lea el nuevo nodo */ new_node.next = head; /* 4. Mover el encabezado de la lista para apuntar al nuevo nodo */ head = new_node; } /* Insertar el nodo después de un nodo determinado */ public void insertAfter(Node prev_node, int new_data) { /* 1. Verificar la presencia de un nodo determinado en la lista vinculada */ if (prev_node == null) { System.out.println("The given previous node cannot be null"); return; } /* 2: establece la ubicación del nodo en la memoria 3: agrega datos */ Node new_node = new Node(new_data); /* 4. Haga que el siguiente del nuevo nodo sea el siguiente del nodo anterior */ new_node.next = prev_node.next; /* 5. Hacer que el nuevo nodo siga al nodo anterior */ prev_node.next = new_node; } /* El método agrega un nuevo nodo al final de la lista de subprocesos */ public void append(int new_data) { /* 1: Reserva la ubicación del nodo en la memoria 2: Agrega datos 3: null Hace lo siguiente para el nuevo nodo */ Node new_node = new Node(new_data); /* Hacer que el nuevo nodo sea el encabezado de la lista si la lista está vacía */ if (head == null) { head = new Node(new_data); return; } /* 4. El nuevo nodo será el último nodo de la lista nulo, por lo que convertiremos el siguiente */ new_node.next = null; /* 5. De lo contrario, pasaremos por los elementos de la lista hasta el último nodo */ Node last = head; while (last.next != null) last = last.next; /* 6. Cambiamos lo siguiente al último nodo */ last.next = new_node; return; } /* Este método imprime el contenido de la lista de subprocesos comenzando desde el nodo dado */ public void printList() { Node tnode = head; while (tnode != null) { System.out.print(tnode.data+" "); tnode = tnode.next; } } /* Probar el código anterior */ public static void main(String[] args) { /* comienza con una lista vacía */ LinkedList llist = new LinkedList(); // Inserte el elemento 6 en la lista, por lo que se convierte // 6-> NUllist llist.append(6); // Inserte el elemento 7 al principio de la lista, de modo que se convierta // 7-> 6-> NUllist llist.push(7); // Inserte el elemento 1 al principio de la lista, por lo que se convierte en // 1-> 7-> 6-> NUllist llist.push(1); // Inserte el elemento 4 al final de la lista, por lo que se convierte en // 1-> 7-> 6-> 4-> NUllist llist.append(4); // Inserta el elemento 8 después del elemento 7 en la lista, por lo que se convierte en // 1-> 7-> 8-> 6-> 4-> NUllist llist.insertAfter(llist.head.next, 8); System.out.println("\n Lista vinculada creada: "); llist.printList(); } }
Eliminar nodos de listas vinculadas
El proceso de eliminación de los nodos de las listas vinculadas se realiza de acuerdo con los siguientes pasos:
- Busque el nodo anterior del nodo que se va a eliminar.
- Cambie el siguiente nodo al nodo anterior.
- Vacíe la memoria reservada por el nodo a borrar.
La siguiente figura muestra el proceso de eliminación de un nodo de la lista de subprocesos:

C reserva dinámicamente memoria para cada nodo en la lista de subprocesos usando la función malloc()
. Por lo tanto, se debe llamar free()
a la función para vaciar la porción de memoria reservada por el nodo a eliminar.
Los siguientes ejemplos muestran cómo eliminar un nodo de la lista de subprocesos en varios lenguajes de programación (C++, Python, Java):
#incluir <stdio.h> #incluir <stdlib.h> // nodo en la lista encadenada struct Node { int data; struct Node *next; } /* La función inserta un nuevo nodo al principio de la lista usando una referencia (puntero a un puntero) al encabezado de la lista y el entero dado */ void push(struct Node** head_ref, int new_data) { struct Node* new_node = (struct Node*) malloc(sizeof(struct Node)); new_node->data = new_data; new_node->next = (*head_ref); (*head_ref) = new_node; } /* La función elimina la primera aparición de la clave dada en la lista encadenada usando una referencia (puntero a un puntero) al encabezado de la lista y la clave dada */ void deleteNode(struct Node **head_ref, int key) { // almacena los nodos de encabezado de la lista struct Node* temp = *head_ref, *prev; // si el nodo del encabezado de la lista es el nodo que contiene la clave que se eliminará if (temp != NULL && temp->data == key) { *head_ref = temp->next; // cambiar el encabezado del menú free(temp); // deshacerse del antiguo encabezado de return; } // Encuentre la clave para eliminar mientras continúa // el nodo anterior porque necesitamos // cambiar el nodo anterior al siguiente nodo // 'prev->next' while (temp != NULL && temp->data != key) { prev = temp; temp = temp->next; } // si la clave no está en la lista de subprocesos if (temp == NULL) return; // desvincular el nodo de la lista de subprocesos prev->next = temp->next; free(temp); // Free memory } // Esta función imprime el contenido de la lista encadenada a partir del nodo dado void printList(struct Node *node) { while (node != NULL) { printf(" %d ", node->data); node = node->next; } } /* Probar las funciones anteriores */ int main() { /* comenzar con un nodo vacío */ struct Node* head = NULL; push(&head, 7); push(&head, 1); push(&head, 3); push(&head, 2); puts("Lista vinculada creada: "); printList(head); deleteNode(&head, 1); puts("\nLinked List after Deletion of 1: "); printList(head); return 0; }
# nodo de clase class Node: # Función del constructor para inicializar el objeto de nodo def __init__(self, data): self.data = data self.next = None class LinkedList: # Inicializa el encabezado de la lista def __init__(self): self.head = None # La función inserta un nuevo nodo al comienzo de la lista def push(self, new_data): new_node = Node(new_data) new_node.next = self.head self.head = new_node # La función elimina la primera aparición de la clave dada en la lista encadenada # usando una referencia al encabezado de la lista y la clave dada def deleteNode(self, key): # almacena la temperatura del nodo temp = self.head # si el nodo principal contiene el valor de la clave dada if (temp is not None): if (temp.data == key): self.head = temp.next temp = None return # Encuentre la clave para eliminar mientras continúa con el # porque la necesitamos para cambiar el nodo posterior del nodo anterior # 'prev.next' while(temp is not None): if temp.data == key: break prev = temp temp = temp.next # Si la clave no está en la lista de subprocesos if(temp == None): return # Desvincular el nodo de la lista de subprocesos prev.next = temp.next temp = None # Utility function to print the linked LinkedList def printList(self): temp = self.head while(temp): print " %d" %(temp.data), temp = temp.next # Probar las funciones anteriores llist = LinkedList() llist.push(7) llist.push(1) llist.push(3) llist.push(2) print "Lista vinculada creada: " llist.printList() llist.deleteNode(1) print "\nLinked List after Deletion of 1:" llist.printList()
class LinkedList { Node head; // al principio de la lista // nodo de lista encadenada class Node { int data; Node next; Node(int d) { data = d; next = null; } } // La función elimina la primera aparición de la clave dada en la lista encadenada void deleteNode(int key) { // almacena el nodo principal Node temp = head, prev = null; // si el propio nodo principal contiene la clave que se eliminará if (temp != null && temp.data == key) { head = temp.next; // cambia el encabezado de la lista return; } // Encuentre la clave para eliminar, continuando // el nodo anterior porque necesitamos cambiar el nodo posterior // temp.next while (temp != null && temp.data != key) { prev = temp; temp = temp.next; } // si la clave no está en la lista de subprocesos if (temp == null) return; // Desvincular el nodo de la lista de subprocesos prev.next = temp.next; } // El método inserta un nuevo nodo al comienzo de la lista de subprocesos public void push(int new_data) { Node new_node = new Node(new_data); new_node.next = head; head = new_node; } /* Esta función imprime el contenido de la lista encadenada a partir del nodo dado */ public void printList() { Node tnode = head; while (tnode != null) { System.out.print(tnode.data+" "); tnode = tnode.next; } } // probar funciones anteriores public static void main(String[] args) { LinkedList llist = new LinkedList(); llist.push(7); llist.push(1); llist.push(3); llist.push(2); System.out.println("\n Lista vinculada creada:"); llist.printList(); llist.deleteNode(1); // elimina el nodo en la ubicación 1 System.out.println("\n Lista enlazada después de la eliminación en la posición 4:"); llist.printList(); } }
El código anterior da el siguiente resultado:
Lista enlazada creada 2 3 1 7 Lista encadenada después de eliminar el elemento 1 2 3 7
Eliminación de un nodo de una lista encadenada en función de la ubicación
Si el nodo a eliminar es el primer nodo, se puede eliminar directamente, de lo contrario debe haber un puntero al nodo anterior del nodo a eliminar. Entonces, si la ubicación es cualquier cosa menos cero, debe repetir iterativamente (ubicación – 1) veces para obtener el puntero al nodo anterior.
Los siguientes ejemplos muestran cómo eliminar un nodo de una lista encadenada según la ubicación:
#include <stdio.h> #include <stdlib.h> // nodo en la lista encadenada struct Node { int data; struct Node *next; } /* La siguiente función inserta un nuevo nodo al frente de la lista encadenada usando un puntero al encabezado de la lista y el entero dado */ void push(struct Node** head_ref, int new_data) { struct Node* new_node = (struct Node*) malloc(sizeof(struct Node)); new_node->data = new_data; new_node->next = (*head_ref); (*head_ref) = new_node; } /* La siguiente función elimina el nodo en la ubicación dada usando una referencia (puntero a un puntero) al encabezado de la lista y la ubicación dada */ void deleteNode(struct Node **head_ref, int position) { // si el la lista if (*head_ref == NULL) return; // almacenar el nodo de encabezado de lista struct Node* temp = *head_ref; // si el nodo a eliminar es if (position == 0) { *head_ref = temp->next; // cambiar el encabezado del menú free (temp); return; } // Encuentre el nodo anterior del nodo a eliminar for (int i=0; temp!=NULL && i<position-1; i++) temp = temp->next; // si la ubicación es mayor que el número de nodos if (temp == NULL || temp->next == NULL) return; // temp->next // es el nodo a eliminar // almacena el puntero al siguiente nodo a eliminar struct Node *next = temp->next->next; // desvincular el nodo de la lista de subprocesos free(temp->next); // Vaciar la memoria ocupada por el nodo temp->next = next; // desvincular el nodo de la lista de hilos } // Esta función imprime el contenido de la lista encadenada a partir del nodo dado void printList(struct Node *node) { while (node != NULL) { printf(" %d ", node->data); node = node->next; } } // prueba las funciones anteriores int main() { // comienza con una lista de subprocesos vacía struct Node* head = NULL; push(&head, 7); push(&head, 1); push(&head, 3); push(&head, 2); push(&head, 8); puts("Lista vinculada creada: "); printList(head); deleteNode(&head, 4); puts("\n Lista enlazada después de la eliminación en la posición 4: "); printList(head); return 0; }
# nodo de clase class Node: # Función del constructor para inicializar el objeto de nodo def __init__(self, data): self.data = data self.next = None class LinkedList: # Inicializa el encabezado de la lista def __init__(self): self.head = None # La función inserta un nuevo nodo al frente de la lista def push(self, new_data): new_node = Node(new_data) new_node.next = self.head self.head = new_node # La siguiente función elimina el nodo en la ubicación dada # usando una bandera del encabezado de la lista y la ubicación dada */ def deleteNode(self, position): # si la lista encadenada está vacía if self.head == None: return # almacena la temperatura del nodo temp = self.head # si se va a eliminar el encabezado de la lista if position == 0: self.head = temp.next temp = None return # Encuentre el nodo anterior del nodo para eliminar for i in range(position -1 ): temp = temp.next if temp is None: break # si la ubicación dada es mayor que el número de elementos en la lista if temp is None: return if temp.next is None: return #temp.next # es el nodo que se eliminará # El puntero se almacena en el nodo que sigue al nodo que se eliminará next = temp.next.next # Desvincular el nodo de la lista de subprocesos temp.next = None temp.next = next # Función de utilidad para imprimir la LinkedList vinculada def printList(self): temp = self.head while(temp): print " %d " %(temp.data), temp = temp.next # Probar las funciones anteriores llist = LinkedList() llist.push(7) llist.push(1) llist.push(3) llist.push(2) llist.push(8) print "Lista vinculada creada: " llist.printList() llist.deleteNode(4) print "\n Lista enlazada después de la eliminación en la posición 4: " llist.printList()
class LinkedList { Node head; // al principio de la lista /* Nodo en la lista de hilos*/ class Node { int data; Node next; Node(int d) { data = d; next = null; } } /* Inserta un nuevo nodo al frente de la lista */ public void push(int new_data) { /* 1: Reserve una ubicación de nodo en la memoria 2: agregue datos */ Node new_node = new Node(new_data); /* 3: Hacer que el siguiente nodo nuevo sea el encabezado de la lista de subprocesos */ new_node.next = head; /* 4: Mover la cabeza para señalar el nuevo nodo */ head = new_node; } /* La función elimina el nodo en la ubicación dada usando un puntero al encabezado y la ubicación dada */ void deleteNode(int position) { // si la lista encadenada está vacía if (head == null) return; // almacena el nodo de cabecera de la lista Node temp = head; // if (position == 0) { head = temp.next; // cambia el encabezado de la lista return ; } // Encuentre el nodo que precede al nodo que se eliminará for (int i=0; temp!=null && i<position-1; i++) temp = temp.next; // si la ubicación solicitada es mayor que el número de nodos en la lista de subprocesos if (temp == null || temp.next == null) return; // temp->next // es el nodo que se eliminará // almacena el puntero al nodo junto al nodo que se eliminará Node next = temp.next.next; temp.next = next; // desvincular el nodo de la lista de hilos } // Esta función imprime el contenido de la lista encadenada a partir del nodo dado public void printList() { Node tnode = head; while (tnode != null) { System.out.print(tnode.data+" "); tnode = tnode.next; } } // prueba los discípulos anteriores public static void main(String[] args) { /* menú de inicio vacío */ LinkedList llist = new LinkedList(); llist.push(7); llist.push(1); llist.push(3); llist.push(2); llist.push(8); llist.printList(); llist.deleteNode(4); // elimina el nodo en la posición 4 System.out.println( "\nLista enlazada después de la eliminación en la posición 4: " ); llist.printList(); } }
El código anterior da el siguiente resultado:
Lista enlazada establecida: 8 2 3 1 7 La lista encadenada después de eliminar el elemento en la posición 4: 8 2 3 1
Buscar un elemento en la lista encadenada
Puede buscar un elemento en la lista encadenada de dos maneras:
- método iterativo.
- método recursivo.
método iterativo
El método iterativo incluye los siguientes pasos:
- inicialización del puntero de nodo,
current = head
- Realice lo siguiente siempre que el valor
current
no seaNull
- Si es
current->key
igual a la clave a buscar, devolvemos el valortrue
. - atribución
current->next
acurrent
- valor de retorno
false
.
- Si es
Los siguientes ejemplos muestran cómo implementar un método iterativo para encontrar un nodo específico en la lista de subprocesos y en varios lenguajes de programación (C++, Python, Java) :
#include <bits/stdc++.h> using namespace std; /* Nodo en la lista de hilos */ class Node { public: int key; Node* next; } /* Esta función agrega un nuevo nodo al frente de la lista encadenada usando una bandera (un puntero a un puntero) al encabezado de la lista y el entero dado */ void push(Node** head_ref, int new_key){ /* Reservar la ubicación del nodo en la memoria */ Node* new_node = new Node(); /* añadir clave */ new_node->key = new_key; /* Separar la lista anterior del nuevo nodo */ new_node->next = (*head_ref); /* Mueve el encabezado de la lista para que apunte al nuevo nodo */ (*head_ref) = new_node; } /* Verifica que el valor dado esté en la lista de subprocesos */ bool search(Node* head, int x) { Node* current = head; // inicializa el nodo actual while (current != NULL) { if (current->key == x) return true; current = current->next; } return false; } /* prueba las funciones anteriores*/ int main() { /* comienza con una lista de subprocesos vacía */ Node* head = NULL; int x = 21; /* push() Usa la función para crear la siguiente lista encadenada : 14->21->11->30->10 */ push(&head, 10); push(&head, 30); push(&head, 11); push(&head, 21); push(&head, 14); search(head, 21)? cout<<"Yes" : cout<<"No"; return 0; }
# nodo de clase class Node: # Inicializar el objeto de nodo def __init__(self, data): self.data = data # Asignar datos self.next = None # Inicializar siguiente como nulo # class LinkedList: def __init__(self): self.head = None # Inicializar el encabezado de la lista # Este método inserta un nuevo nodo al comienzo de la lista encadenada def push(self, new_data): # crear un nuevo nodo new_node = Node(new_data) # Hacer el encabezado de la lista después de new_node.next = self.head # Mueva el encabezado para que apunte al nuevo nodo self.head = new_node # Esta función verifica si el valor dado existe en la lista de subprocesos def search(self, x): # Inicializa el encabezado current = self.head # Repetir hasta que el valor de # Ninguno para el nodo actual sea while current != None: if current.data == x: return True # datos encontrados current = current.next return False # No se encontraron los datos solicitados # Probar las funciones anteriores if __name__ == '__main__': # comenzar con una lista vacía llist = LinkedList() ''' Usamos el método push() para crear la siguiente lista encadenada : 14->21->11->30->10 ''' llist.push(10); llist.push(30); llist.push(11); llist.push(21); llist.push(14); if llist.search(21): print("Si") else: print("No")
// clase noo class Node { int data; Node next; Node(int d) { data = d; next = null; } } class LinkedList { Node head; // al principio de la lista // inserta un nodo al principio de la lista public void push(int new_data) { // reserva una ubicación para el nuevo nodo en la memoria y agrega datos Node new_node = new Node(new_data); // Hacer que el encabezado de la lista siga al siguiente nodo new_node.next = head; // mueve el encabezado de la lista para que apunte al nuevo nodo head = new_node; } // Comprueba si el valor dado está en la lista de subprocesos de public boolean search(Node head, int x) { Node current = head; // inicializa el encabezado actual while (current != null) { if (current.data == x) return true; // Se encontraron los datos solicitados current = current.next; } return false; } // Probar las funciones anteriores public static void main(String args[]) { // comenzar con una lista LinkedList llist = new LinkedList(); /* Usa el método push() para crear la siguiente lista encadenada 14->21->11->30->10 */ llist.push(10); llist.push(30); llist.push(11); llist.push(21); llist.push(14); if (llist.search(llist.head, 21)) System.out.println("Si"); else System.out.println("No"); } }
El código anterior da el siguiente resultado:
Sí
Método recursivo
La función trabaja search(head, x)
de manera recursiva de acuerdo a los siguientes pasos:
- Si el vértice es igual,
Null
la función devuelve el valorfalse
. - Si la clave para el encabezado es la
x
misma, la función devuelve el valortrue
. - De lo contrario, la función devuelve el resultado de la llamada a la función
search(head->next, x)
.
Los siguientes ejemplos muestran cómo realizar una búsqueda recursiva en varios lenguajes de programación (C, Python, Java) :
#include<stdio.h> #include<stdlib.h> #include<stdbool.h> /* Nodo en la lista de hilos */ struct Node { int key; struct Node* next; } /* La función inserta un nuevo nodo al frente de la lista encadenada usando un puntero al encabezado de la lista y el entero dado */ void push(struct Node** head_ref, int new_key) { /* Reservar la ubicación del nodo en la memoria */ struct Node* new_node = (struct Node*) malloc(sizeof(struct Node)); /* añadir clave */ new_node->key = new_key; /* Desconexión entre la lista de subprocesos y el nuevo nodo */ new_node->next = (*head_ref); /* Mueve el encabezado de la lista para que apunte al nuevo nodo */ (*head_ref) = new_node; } /* Comprobar si el valor dado está en la lista de subprocesos */ bool search(struct Node* head, int x) { // Prerequisito if (head == NULL) return false; // devuelve verdadero si la clave requerida está en la lista if (head->key == x) return true; // La función se ejecuta recursivamente para encontrar la clave requerida return search(head->next, x); } /* Probar las funciones anteriores*/ int main(){ /* comenzar con una lista vacía */ struct Node* head = NULL; int x = 21; /* La función push() se usa para crear la siguiente lista encadenada 14->21->11->30->10 */ push(&head, 10); push(&head, 30); push(&head, 11); push(&head, 21); push(&head, 14); search(head, 21)? printf("Si") : printf("No"); return 0; }
# nodo de clase class node : # Inicializar el objeto de nodo def __init__(self, data): self.data = data # Asignar datos self.next = None # Inicializar siguiente como nulo # Ordenar la lista enlazada class LinkedList: def __init__(self): self.head = None # Inicializar el encabezado de la lista # Este método inserta un nuevo nodo al principio de la lista de subprocesos def push(self, new_data): # crear un nuevo nodo new_node = Node(new_data) # Hacer el encabezado de la lista después de new_node.next = self.head # Mueva el encabezado para que apunte al nuevo nodo self.head = new_node # Esta función comprueba si el valor dado existe en la lista de subprocesos def search(self, li, key): # requisito previo if(not li): return False # devuelve verdadero # si la clave está en el nodo actual if(li.data == key): return True # Ejecuta la función de forma recursiva en el resto de los nodos de la lista de subprocesos return self.search(li.next, key) # Probar las funciones anteriores if __name__ == '__main__': # comenzar con una lista vacía llist = LinkedList() ''' Usamos el método push() para crear la siguiente lista encadenada: 14->21->11->30->10 ''' llist.push(10); llist.push(30); llist.push(11); llist.push(21); llist.push(14); if llist.search(21): print("Si") else: print("No")
// Nodo de clase class Node { int data; Node next; Node(int d) { data = d; next = null; } } // Ordenar la lista enlazada class LinkedList { Node head; // al principio de la lista // inserta un nodo al principio de la lista public void push(int new_data) { // reserva una ubicación para el nuevo nodo en la memoria y agrega datos Node new_node = new Node(new_data); // Hacer que el encabezado de la lista siga al siguiente nodo new_node.next = head; // mueve el encabezado de la lista para que apunte al nuevo nodo head = new_node; } // Verifique que el valor dado esté en la lista de subprocesos public boolean search(Node head, int x) { // Requisito previo if (head == null) return false; // devuelve verdadero // si la clave está en el nodo actual if (head.data == x) return true; // Ejecuta una función recursiva en el resto de los nodos en la lista de subprocesos return search(head.next, x); } // Probar las funciones anteriores public static void main(String args[]) { // comenzar con una lista enlazada vacía LinkedList llist = new LinkedList(); /* Usa el método push() para crear la siguiente lista encadenada 14->21->11->30->10 */ llist.push(10); llist.push(30); llist.push(11); llist.push(21); llist.push(14); if (llist.search(llist.head, 21)) System.out.println("Si"); else System.out.println("No"); } }
Fuente
- La página en GeeksforGeeks de estructura de datos de lista enlazada.
- Página de la documentación de estructuras de datos en el sitio GeeksforGeeks lista enlazada | Conjunto 1 (Introducción).
- Página documentación de estructuras de datos en el sitio GeeksforGeeks de lista enlazada | Conjunto 2 (Inserción de un nodo).
- Página documentación de estructuras de datos en el sitio GeeksforGeeks de lista enlazada | Conjunto 3 (Eliminación de un nodo).