Lista enlazada
Una secuencia de nodos en la que cada uno guarda un valor y una referencia al siguiente. Insertar o borrar en un punto ya localizado es O(1), sin mover nada; llegar a una posición cuesta O(n).
Visualízalo paso a paso
Cambia los datos, dale a reproducir y sigue cada paso en el dibujo, en la línea de Java que se ejecuta y en sus variables.
Lista enlazada
Escribe las operaciones (principio x, final x o borrar x) y mira cómo se crean nodos y se cambian las flechas, sin mover ningún dato.
Paso 1
Una lista vacía: cabeza no apunta a ningún nodo (null). Cada nodo guarda un valor y una referencia al siguiente.
1class Lista {
2 private Nodo cabeza;
3
4 void alPrincipio(int x) {
5 Nodo n = new Nodo(x);
6 n.siguiente = cabeza;
7 cabeza = n;
8 }
9
10 void alFinal(int x) {
11 Nodo n = new Nodo(x);
12 if (cabeza == null) { cabeza = n; return; }
13 Nodo p = cabeza;
14 while (p.siguiente != null) p = p.siguiente;
15 p.siguiente = n;
16 }
17
18 boolean borrar(int x) {
19 if (cabeza == null) return false;
20 if (cabeza.valor == x) { cabeza = cabeza.siguiente; return true; }
21 Nodo p = cabeza;
22 while (p.siguiente != null && p.siguiente.valor != x) p = p.siguiente;
23 if (p.siguiente == null) return false;
24 p.siguiente = p.siguiente.siguiente;
25 return true;
26 }
27}Variables
- lista
- vacía
Atajos con el foco dentro del visualizador: ← → paso a paso, Espacio reproducir o pausar, Inicio/Fin ir al principio o al final.
La idea
En un array los elementos están seguidos en memoria: por eso se llega a cualquiera en O(1) con su índice, pero insertar o borrar en medio obliga a desplazar todos los que van detrás.
Una lista enlazada hace lo contrario. Cada elemento vive en su propio objeto, un nodo, que guarda el valor y una referencia (una flecha) al siguiente nodo. La lista solo necesita saber dónde está el primero, la cabeza; el último apunta a null. Los nodos pueden estar en cualquier parte de la memoria.
Insertar un nodo nuevo o quitar uno es cambiar un par de flechas, O(1), sin mover ningún dato... siempre que ya se tenga el nodo anterior. El precio es que no hay acceso directo: para llegar al elemento 1.000 hay que recorrer 999 flechas desde la cabeza, O(n). Además cada nodo ocupa bastante más memoria que una casilla de un array.
Hay variantes: la doblemente enlazada guarda también una flecha al anterior (permite recorrer hacia atrás y borrar un nodo conociendo solo ese nodo), y la circular hace que el último apunte al primero. LinkedList de Java es doblemente enlazada.
Cuándo usarlo
- Muchas inserciones y borrados al principio o en un punto que ya se tiene localizado (por ejemplo, mientras se recorre).
- Como base de otras estructuras: pilas, colas, las listas de las cubetas de una tabla hash, las listas de adyacencia de un grafo.
- Para entender las referencias de Java: es el ejercicio clásico para dominar
null, la asignación de referencias y la recursividad sobre estructuras.
Cuándo no
- Si se accede por posición (
get(i)): en un array es O(1) y en una lista enlazada O(n). Por esoArrayListes la opción por defecto en Java. - Si importa la memoria o la velocidad de recorrido: los nodos dispersos en memoria aprovechan muy mal la caché.
Paso a paso
- El nodo. Una clase con dos campos:
valorysiguiente, una referencia a otro nodo (onullsi es el último). - Insertar al principio. Nodo nuevo cuyo
siguientees la cabeza actual; después, la cabeza pasa a ser el nodo nuevo. Dos asignaciones, O(1). - Recorrer.
for (Nodo p = cabeza; p != null; p = p.siguiente): se avanza de flecha en flecha hastanull. - Borrar. Se busca el nodo anterior al que se borra y se hace que se lo salte:
anterior.siguiente = anterior.siguiente.siguiente. Si es la cabeza, la cabeza pasa al segundo.
El código
Una lista enlazada con referencia al último
Guardar también el último nodo hace que añadir al final sea O(1); hay que acordarse de actualizarlo al borrar.
1public class Main {
2 static class Nodo {
3 int valor;
4 Nodo siguiente;
5 Nodo(int valor) { this.valor = valor; }
6 }
7
8 /** Lista simplemente enlazada con referencia al primero y al último. */
9 static class Lista {
10 private Nodo cabeza, ultimo;
11 private int tam = 0;
12
13 void alPrincipio(int x) { // O(1)
14 Nodo n = new Nodo(x);
15 n.siguiente = cabeza;
16 cabeza = n;
17 if (ultimo == null) ultimo = n;
18 tam++;
19 }
20
21 void alFinal(int x) { // O(1) gracias a la referencia al último
22 Nodo n = new Nodo(x);
23 if (ultimo == null) cabeza = n;
24 else ultimo.siguiente = n;
25 ultimo = n;
26 tam++;
27 }
28
29 boolean borrar(int x) { // O(n): hay que encontrar al anterior
30 Nodo anterior = null, p = cabeza;
31 while (p != null && p.valor != x) { anterior = p; p = p.siguiente; }
32 if (p == null) return false;
33 if (anterior == null) cabeza = p.siguiente; // era el primero
34 else anterior.siguiente = p.siguiente; // el anterior se salta a p
35 if (p == ultimo) ultimo = anterior;
36 tam--;
37 return true;
38 }
39
40 @Override public String toString() {
41 StringBuilder sb = new StringBuilder("[");
42 for (Nodo p = cabeza; p != null; p = p.siguiente) sb.append(p.valor).append(p.siguiente != null ? " → " : "");
43 return sb.append("] (").append(tam).append(tam == 1 ? " nodo)" : " nodos)").toString();
44 }
45 }
46
47 public static void main(String[] args) {
48 Lista l = new Lista();
49 l.alFinal(3);
50 l.alFinal(7);
51 l.alPrincipio(1);
52 l.alFinal(9);
53 System.out.println(l);
54 l.borrar(7);
55 System.out.println("Tras borrar el 7: " + l);
56 l.borrar(1);
57 l.borrar(9);
58 System.out.println("Tras borrar el 1 y el 9: " + l);
59 }
60}class Nodo:
def __init__(self, valor):
self.valor = valor
self.siguiente = None
class Lista:
"""Lista simplemente enlazada con referencia al primero y al último."""
def __init__(self):
self.cabeza = self.ultimo = None
self.tam = 0
def al_principio(self, x): # O(1)
n = Nodo(x)
n.siguiente = self.cabeza
self.cabeza = n
if self.ultimo is None:
self.ultimo = n
self.tam += 1
def al_final(self, x): # O(1) gracias a la referencia al último
n = Nodo(x)
if self.ultimo is None:
self.cabeza = n
else:
self.ultimo.siguiente = n
self.ultimo = n
self.tam += 1
def borrar(self, x): # O(n): hay que encontrar al anterior
anterior, p = None, self.cabeza
while p is not None and p.valor != x:
anterior, p = p, p.siguiente
if p is None:
return False
if anterior is None:
self.cabeza = p.siguiente # era el primero
else:
anterior.siguiente = p.siguiente # el anterior se salta a p
if p is self.ultimo:
self.ultimo = anterior
self.tam -= 1
return True
def __str__(self):
valores, p = [], self.cabeza
while p:
valores.append(str(p.valor))
p = p.siguiente
return "[" + " → ".join(valores) + f"] ({self.tam} {'nodo' if self.tam == 1 else 'nodos'})"
l = Lista()
l.al_final(3)
l.al_final(7)
l.al_principio(1)
l.al_final(9)
print(l)
l.borrar(7)
print("Tras borrar el 7:", l)
l.borrar(1)
l.borrar(9)
print("Tras borrar el 1 y el 9:", l)class Nodo {
constructor(valor) {
this.valor = valor;
this.siguiente = null;
}
}
/** Lista simplemente enlazada con referencia al primero y al último. */
class Lista {
cabeza = null;
ultimo = null;
tam = 0;
alPrincipio(x) { // O(1)
const n = new Nodo(x);
n.siguiente = this.cabeza;
this.cabeza = n;
if (this.ultimo === null) this.ultimo = n;
this.tam++;
}
alFinal(x) { // O(1) gracias a la referencia al último
const n = new Nodo(x);
if (this.ultimo === null) this.cabeza = n;
else this.ultimo.siguiente = n;
this.ultimo = n;
this.tam++;
}
borrar(x) { // O(n): hay que encontrar al anterior
let anterior = null, p = this.cabeza;
while (p !== null && p.valor !== x) { anterior = p; p = p.siguiente; }
if (p === null) return false;
if (anterior === null) this.cabeza = p.siguiente; // era el primero
else anterior.siguiente = p.siguiente; // el anterior se salta a p
if (p === this.ultimo) this.ultimo = anterior;
this.tam--;
return true;
}
toString() {
const v = [];
for (let p = this.cabeza; p !== null; p = p.siguiente) v.push(p.valor);
return `[${v.join(" → ")}] (${this.tam} ${this.tam === 1 ? "nodo" : "nodos"})`;
}
}
const l = new Lista();
l.alFinal(3);
l.alFinal(7);
l.alPrincipio(1);
l.alFinal(9);
console.log(String(l));
l.borrar(7);
console.log("Tras borrar el 7: " + l);
l.borrar(1);
l.borrar(9);
console.log("Tras borrar el 1 y el 9: " + l);using System;
using System.Collections.Generic;
class Nodo {
public int Valor;
public Nodo? Siguiente;
public Nodo(int valor) { Valor = valor; }
}
// Lista simplemente enlazada con referencia al primero y al último.
class Lista {
private Nodo? cabeza, ultimo;
private int tam = 0;
public void AlPrincipio(int x) { // O(1)
var n = new Nodo(x) { Siguiente = cabeza };
cabeza = n;
ultimo ??= n;
tam++;
}
public void AlFinal(int x) { // O(1) gracias a la referencia al último
var n = new Nodo(x);
if (ultimo == null) cabeza = n;
else ultimo.Siguiente = n;
ultimo = n;
tam++;
}
public bool Borrar(int x) { // O(n): hay que encontrar al anterior
Nodo? anterior = null, p = cabeza;
while (p != null && p.Valor != x) { anterior = p; p = p.Siguiente; }
if (p == null) return false;
if (anterior == null) cabeza = p.Siguiente; // era el primero
else anterior.Siguiente = p.Siguiente; // el anterior se salta a p
if (p == ultimo) ultimo = anterior;
tam--;
return true;
}
public override string ToString() {
var v = new List<int>();
for (var p = cabeza; p != null; p = p.Siguiente) v.Add(p.Valor);
return quot;[{string.Join(" → ", v)}] ({tam} {(tam == 1 ? "nodo" : "nodos")})";
}
}
class Program {
static void Main() {
var l = new Lista();
l.AlFinal(3);
l.AlFinal(7);
l.AlPrincipio(1);
l.AlFinal(9);
Console.WriteLine(l);
l.Borrar(7);
Console.WriteLine("Tras borrar el 7: " + l);
l.Borrar(1);
l.Borrar(9);
Console.WriteLine("Tras borrar el 1 y el 9: " + l);
}
}<?php
class Nodo {
public ?Nodo $siguiente = null;
public function __construct(public int $valor) { }
}
/** Lista simplemente enlazada con referencia al primero y al último. */
class Lista {
private ?Nodo $cabeza = null;
private ?Nodo $ultimo = null;
private int $tam = 0;
public function alPrincipio(int $x): void { // O(1)
$n = new Nodo($x);
$n->siguiente = $this->cabeza;
$this->cabeza = $n;
$this->ultimo ??= $n;
$this->tam++;
}
public function alFinal(int $x): void { // O(1) gracias a la referencia al último
$n = new Nodo($x);
if ($this->ultimo === null) $this->cabeza = $n;
else $this->ultimo->siguiente = $n;
$this->ultimo = $n;
$this->tam++;
}
public function borrar(int $x): bool { // O(n): hay que encontrar al anterior
$anterior = null;
$p = $this->cabeza;
while ($p !== null && $p->valor !== $x) { $anterior = $p; $p = $p->siguiente; }
if ($p === null) return false;
if ($anterior === null) $this->cabeza = $p->siguiente; // era el primero
else $anterior->siguiente = $p->siguiente; // el anterior se salta a $p
if ($p === $this->ultimo) $this->ultimo = $anterior;
$this->tam--;
return true;
}
public function __toString(): string {
$v = [];
for ($p = $this->cabeza; $p !== null; $p = $p->siguiente) $v[] = $p->valor;
return "[" . implode(" → ", $v) . "] ({$this->tam} " . ($this->tam === 1 ? "nodo" : "nodos") . ")";
}
}
$l = new Lista();
$l->alFinal(3);
$l->alFinal(7);
$l->alPrincipio(1);
$l->alFinal(9);
echo $l, "\n";
$l->borrar(7);
echo "Tras borrar el 7: $l\n";
$l->borrar(1);
$l->borrar(9);
echo "Tras borrar el 1 y el 9: $l\n";Salida al ejecutarlo (la misma en los 5 lenguajes)
[1 → 3 → 7 → 9] (4 nodos) Tras borrar el 7: [1 → 3 → 9] (3 nodos) Tras borrar el 1 y el 9: [3] (1 nodo)
Invertir una lista
La pregunta de entrevista más clásica sobre listas: darle la vuelta cambiando solo las flechas, con tres referencias.
1/** Invierte la lista sin crear nodos nuevos: se le da la vuelta a cada flecha. */
2static Nodo invertir(Nodo cabeza) {
3 Nodo anterior = null, actual = cabeza;
4 while (actual != null) {
5 Nodo siguiente = actual.siguiente; // se guarda antes de perderlo
6 actual.siguiente = anterior; // la flecha apunta hacia atrás
7 anterior = actual;
8 actual = siguiente;
9 }
10 return anterior; // el que era el último es la nueva cabeza
11}def invertir(cabeza):
"""Invierte la lista sin crear nodos nuevos: se le da la vuelta a cada flecha."""
anterior, actual = None, cabeza
while actual is not None:
siguiente = actual.siguiente # se guarda antes de perderlo
actual.siguiente = anterior # la flecha apunta hacia atrás
anterior, actual = actual, siguiente
return anterior # el que era el último es la nueva cabeza/** Invierte la lista sin crear nodos nuevos: se le da la vuelta a cada flecha. */
function invertir(cabeza) {
let anterior = null, actual = cabeza;
while (actual !== null) {
const siguiente = actual.siguiente; // se guarda antes de perderlo
actual.siguiente = anterior; // la flecha apunta hacia atrás
anterior = actual;
actual = siguiente;
}
return anterior; // el que era el último es la nueva cabeza
}// Invierte la lista sin crear nodos nuevos: se le da la vuelta a cada flecha.
static Nodo? Invertir(Nodo? cabeza) {
Nodo? anterior = null, actual = cabeza;
while (actual != null) {
Nodo? siguiente = actual.Siguiente; // se guarda antes de perderlo
actual.Siguiente = anterior; // la flecha apunta hacia atrás
anterior = actual;
actual = siguiente;
}
return anterior; // el que era el último es la nueva cabeza
}/** Invierte la lista sin crear nodos nuevos: se le da la vuelta a cada flecha. */
function invertir(?Nodo $cabeza): ?Nodo {
$anterior = null;
$actual = $cabeza;
while ($actual !== null) {
$siguiente = $actual->siguiente; // se guarda antes de perderlo
$actual->siguiente = $anterior; // la flecha apunta hacia atrás
$anterior = $actual;
$actual = $siguiente;
}
return $anterior; // el que era el último es la nueva cabeza
}Traza: operaciones sobre una lista vacía
| Operación | Lista | Qué cambia |
|---|---|---|
| alFinal(3) | 3 → null | recorre la lista hasta el último (O(n)), o usa la referencia al último (O(1)) |
| alFinal(7) | 3 → 7 → null | recorre la lista hasta el último (O(n)), o usa la referencia al último (O(1)) |
| alPrincipio(1) | 1 → 3 → 7 → null | nodo nuevo → antigua cabeza; cabeza → nodo nuevo (O(1)) |
| alFinal(9) | 1 → 3 → 7 → 9 → null | recorre la lista hasta el último (O(n)), o usa la referencia al último (O(1)) |
| borrar(7) | 1 → 3 → 9 → null | el anterior pasa a apuntar al siguiente del borrado |
| alPrincipio(4) | 4 → 1 → 3 → 9 → null | nodo nuevo → antigua cabeza; cabeza → nodo nuevo (O(1)) |
Ningún valor se ha movido nunca de su nodo: solo cambian las referencias.
Complejidad
| Operación | Lista enlazada | Array (ArrayList) |
|---|---|---|
| Acceder a la posición i | O(n) | O(1) |
| Insertar o borrar al principio | O(1) | O(n) |
| Insertar o borrar en medio (ya localizado) | O(1) | O(n) |
| Insertar al final | O(1) con referencia al último | O(1) amortizado |
| Buscar un valor | O(n) | O(n) |
Memoria: O(n), pero cada nodo lleva la sobrecarga de un objeto y de las referencias (en Java, unos 24-40 bytes por nodo frente a 4 de un int en un array).
- Mejor caso: O(1)
- Caso medio: O(n)
- Peor caso: O(n)
Insertar o borrar al principio es O(1); buscar, llegar a una posición o insertar al final sin referencia al último es O(n). Las curvas grises son las demás clases, para comparar.
En la práctica
LinkedListde Java (doblemente enlazada) implementaListyDeque; aun así,ArrayListyArrayDequeson más rápidas en casi todos los casos.- Las cubetas de
HashMapson listas enlazadas (que pasan a árboles si se alargan demasiado). - Los sistemas de ficheros FAT encadenan los bloques de un fichero como una lista enlazada.
- La lista de procesos del núcleo de Linux y las cachés LRU (lista doblemente enlazada + tabla hash) se apoyan en listas enlazadas.
Errores típicos
- Perder la referencia a la cabeza al recorrer con ella misma (
cabeza = cabeza.siguiente): la lista se pierde. Se recorre con otra variable. - No comprobar
nullantes dep.siguiente:NullPointerExceptioncon la lista vacía o al llegar al final. - Al borrar, no tratar aparte el caso de la cabeza (no tiene anterior).
- Con referencia al último, olvidar actualizarla al borrar el último nodo.
- Al invertir, cambiar
actual.siguientesin haber guardado antes el siguiente: se corta la lista.
Ejercicios
Cada ejercicio se corrige solo con sus pruebas (algunas ocultas). Escribe tu solución en el editor y pulsa Ejecutar o Comprobar; la solución explicada está debajo, por si te atascas.
1. Lista ordenada con órdenes
Mantén una lista enlazada siempre ordenada de menor a mayor. Las órdenes llegan una por línea: insertar x mete x en su sitio, borrar x quita la primera aparición de x y mostrar escribe la lista. La lista está hecha con una clase Nodo (nada de ArrayList): completa insertarOrdenado y borrar.
- Órdenes:
insertar 5,borrar 5,mostrar(enteros de hasta 6 cifras, también negativos). mostrar:1 → 3 → 5o(vacía). Borrar algo que no está:5 no está.- Otra orden:
Orden no válida: «…».
Ejemplo
insertar 5 insertar 1 insertar 9 insertar 3 mostrar
1 → 3 → 5 → 9
Ver la solución explicada
1import java.util.*;
2
3public class Main {
4 static class Nodo {
5 int valor;
6 Nodo siguiente;
7 Nodo(int valor, Nodo siguiente) { this.valor = valor; this.siguiente = siguiente; }
8 }
9
10 static Nodo cabeza = null;
11
12 /** Inserta x dejando la lista ordenada de menor a mayor (los repetidos, detrás de sus iguales). */
13 static void insertarOrdenado(int x) {
14 if (cabeza == null || x < cabeza.valor) {
15 cabeza = new Nodo(x, cabeza);
16 return;
17 }
18 Nodo p = cabeza;
19 while (p.siguiente != null && p.siguiente.valor <= x) p = p.siguiente;
20 p.siguiente = new Nodo(x, p.siguiente);
21 }
22
23 /** Borra la primera aparición de x; devuelve si estaba. */
24 static boolean borrar(int x) {
25 if (cabeza == null) return false;
26 if (cabeza.valor == x) {
27 cabeza = cabeza.siguiente;
28 return true;
29 }
30 Nodo p = cabeza;
31 while (p.siguiente != null && p.siguiente.valor != x) p = p.siguiente;
32 if (p.siguiente == null) return false;
33 p.siguiente = p.siguiente.siguiente;
34 return true;
35 }
36
37 static String texto() {
38 if (cabeza == null) return "(vacía)";
39 StringJoiner sj = new StringJoiner(" → ");
40 for (Nodo p = cabeza; p != null; p = p.siguiente) sj.add(String.valueOf(p.valor));
41 return sj.toString();
42 }
43
44 public static void main(String[] args) {
45 Scanner sc = new Scanner(System.in);
46 while (sc.hasNextLine()) {
47 String linea = sc.nextLine().trim();
48 if (linea.isEmpty()) continue;
49 if (linea.matches("insertar -?\\d{1,6}")) insertarOrdenado(Integer.parseInt(linea.substring(9)));
50 else if (linea.matches("borrar -?\\d{1,6}")) {
51 int x = Integer.parseInt(linea.substring(7));
52 if (!borrar(x)) System.out.println(x + " no está");
53 } else if (linea.equals("mostrar")) System.out.println(texto());
54 else System.out.println("Orden no válida: «" + linea + "»");
55 }
56 }
57}La inserción ordenada es un solo paso de la ordenación por inserción: encontrar el sitio es O(n), pero meter el nodo es O(1), sin desplazar nada.
Avanzar con <= deja los repetidos detrás de sus iguales: la lista conserva el orden de llegada de los iguales.
2. El medio y el k-ésimo desde el final, en una pasada
La primera línea son los valores de la lista, en orden. Cada línea siguiente es una consulta: medio o final k. Respóndelas recorriendo la lista una sola vez y sin contar antes cuántos nodos tiene: para el medio, una «liebre» que avanza de dos en dos y una «tortuga» de uno en uno; para el k-ésimo desde el final, un puntero que sale con k nodos de ventaja. Completa medio y desdeElFinal.
- Entrada:
1 2 3 4 5y luego consultas comomedioofinal 2. - Salida:
Medio: 3(con un número par de nodos, el segundo de los dos del medio) y2º desde el final: 4, oLa lista no tiene 9 nodos. - Errores:
Número no válido: «x»,La lista está vacíayConsulta no válida: «…».
Ejemplo
1 2 3 4 5 medio final 1 final 2 final 5
Medio: 3 1º desde el final: 5 2º desde el final: 4 5º desde el final: 1
Ver la solución explicada
1import java.util.*;
2
3public class Main {
4 static class Nodo {
5 final int valor;
6 Nodo siguiente;
7 Nodo(int valor) { this.valor = valor; }
8 }
9
10 /** El nodo del medio en una sola pasada: la liebre avanza de dos en dos y la tortuga de uno en uno.
11 Con un número par de nodos, el segundo de los dos del medio. */
12 static Nodo medio(Nodo cabeza) {
13 Nodo tortuga = cabeza, liebre = cabeza;
14 while (liebre != null && liebre.siguiente != null) {
15 tortuga = tortuga.siguiente;
16 liebre = liebre.siguiente.siguiente;
17 }
18 return tortuga;
19 }
20
21 /** El k-ésimo contando desde el final (k = 1 es el último), en una sola pasada: un puntero sale con
22 k nodos de ventaja. null si la lista tiene menos de k nodos. */
23 static Nodo desdeElFinal(Nodo cabeza, int k) {
24 Nodo delante = cabeza;
25 for (int i = 0; i < k; i++) {
26 if (delante == null) return null;
27 delante = delante.siguiente;
28 }
29 Nodo detras = cabeza;
30 while (delante != null) {
31 delante = delante.siguiente;
32 detras = detras.siguiente;
33 }
34 return detras;
35 }
36
37 public static void main(String[] args) {
38 Scanner sc = new Scanner(System.in);
39 String primera = sc.hasNextLine() ? sc.nextLine().trim() : "";
40 Nodo cabeza = null, ultimo = null;
41 if (!primera.isEmpty()) {
42 for (String t : primera.split("\\s+")) {
43 if (!t.matches("-?\\d{1,6}")) {
44 System.out.println("Número no válido: «" + t + "»");
45 return;
46 }
47 Nodo n = new Nodo(Integer.parseInt(t));
48 if (cabeza == null) cabeza = n;
49 else ultimo.siguiente = n;
50 ultimo = n;
51 }
52 }
53 if (cabeza == null) {
54 System.out.println("La lista está vacía");
55 return;
56 }
57 while (sc.hasNextLine()) {
58 String linea = sc.nextLine().trim();
59 if (linea.isEmpty()) continue;
60 if (linea.equals("medio")) System.out.println("Medio: " + medio(cabeza).valor);
61 else if (linea.matches("final [1-9]\\d{0,5}")) {
62 int k = Integer.parseInt(linea.substring(6));
63 Nodo n = desdeElFinal(cabeza, k);
64 System.out.println(n == null ? "La lista no tiene " + k + " nodos" : k + "º desde el final: " + n.valor);
65 } else System.out.println("Consulta no válida: «" + linea + "»");
66 }
67 }
68}Las dos son la técnica de los dos punteros aplicada a listas: dos referencias que avanzan a distinta velocidad o con ventaja resuelven en una pasada lo que, si no, pediría contar primero los nodos.
La liebre y la tortuga (algoritmo de Floyd) sirven también para detectar si una lista tiene un ciclo: si lo tiene, la liebre acaba alcanzando a la tortuga.
Test
Test: Lista enlazada
0/5 respondidas · 0 aciertosElige una respuesta en cada pregunta: verás al momento si es correcta y por qué. Con un 80 % de aciertos se da por superada.
1.¿Cuánto cuesta acceder al elemento i de una lista enlazada?
2.¿Qué operación es O(1) en una lista enlazada y O(n) en un ArrayList?
3.Para borrar un nodo de una lista simplemente enlazada, ¿qué hace falta?
4.¿Qué pasa si se recorre la lista con
cabeza = cabeza.siguiente?5.¿Qué tipo de lista es java.util.LinkedList?