0Pricing
C Academy · Lección

Listas doblemente enlazadas

Enlaces bidireccionales

Listas doblemente enlazadas es una lección gratuita de C Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C Academy incluye 4 lecciones en total.

Enlaces en ambas direcciones

Una lista doblemente enlazada proporciona a cada nodo dos punteros: uno al nodo next y otro al nodo prev (anterior).

Esto permite recorrer la lista en ambas direcciones y simplifica la eliminación.

#include <stdio.h>

struct Node {
    int value;
    struct Node *prev;
    struct Node *next;
};

int main(void) {
    printf("Each node links forward and backward\n");
    return 0;
}

Definir el nodo

La estructura añade un puntero prev junto a next. Ambos son NULL en los extremos de la lista.

#include <stdio.h>
#include <stdlib.h>

struct Node { int value; struct Node *prev; struct Node *next; };

int main(void) {
    struct Node *n = malloc(sizeof(struct Node));
    n->value = 1; n->prev = NULL; n->next = NULL;
    printf("%d\n", n->value);
    free(n);
    return 0;
}

Un ayudante para crear nodos

Como antes, una función auxiliar centraliza la reserva de memoria. Establece prev y next en NULL.

#include <stdio.h>
#include <stdlib.h>

struct Node { int value; struct Node *prev; struct Node *next; };

struct Node *make(int v) {
    struct Node *n = malloc(sizeof(struct Node));
    n->value = v; n->prev = NULL; n->next = NULL;
    return n;
}

int main(void) {
    struct Node *n = make(42);
    printf("%d\n", n->value);
    free(n);
    return 0;
}

Enlazar nodos en ambas direcciones

Al conectar dos nodos, debe actualizar ambas direcciones: el next del primer nodo y el prev del segundo.

#include <stdio.h>
#include <stdlib.h>

struct Node { int value; struct Node *prev; struct Node *next; };
struct Node *make(int v){struct Node*n=malloc(sizeof*n);n->value=v;n->prev=NULL;n->next=NULL;return n;}

int main(void) {
    struct Node *a = make(1), *b = make(2);
    a->next = b;
    b->prev = a;
    printf("forward %d, back %d\n", a->next->value, b->prev->value);
    free(a); free(b);
    return 0;
}

Insertar al principio

Para insertar al principio: el next del nodo nuevo es el head antiguo, el prev del head antiguo es el nodo nuevo y, después, el head pasa a ser el nodo nuevo.

#include <stdio.h>
#include <stdlib.h>

struct Node { int value; struct Node *prev; struct Node *next; };
struct Node *make(int v){struct Node*n=malloc(sizeof*n);n->value=v;n->prev=NULL;n->next=NULL;return n;}

void push(struct Node **head, int v) {
    struct Node *n = make(v);
    n->next = *head;
    if (*head) (*head)->prev = n;
    *head = n;
}

int main(void) {
    struct Node *head = NULL;
    push(&head, 2); push(&head, 1);
    printf("%d %d\n", head->value, head->next->value);
    return 0;
}

Recorrido hacia delante

Recorrer hacia delante es idéntico a hacerlo en una lista simplemente enlazada: siga next hasta NULL.

#include <stdio.h>
#include <stdlib.h>

struct Node { int value; struct Node *prev; struct Node *next; };
struct Node *make(int v){struct Node*n=malloc(sizeof*n);n->value=v;n->prev=NULL;n->next=NULL;return n;}

int main(void) {
    struct Node *a = make(1), *b = make(2);
    a->next = b; b->prev = a;
    for (struct Node *p = a; p; p = p->next) printf("%d ", p->value);
    printf("\n");
    free(a); free(b);
    return 0;
}

Recorrido hacia atrás

La gran ventaja es que, desde cualquier nodo, puede recorrer la lista hacia atrás siguiendo los punteros prev hasta llegar al head.

#include <stdio.h>
#include <stdlib.h>

struct Node { int value; struct Node *prev; struct Node *next; };
struct Node *make(int v){struct Node*n=malloc(sizeof*n);n->value=v;n->prev=NULL;n->next=NULL;return n;}

int main(void) {
    struct Node *a = make(1), *b = make(2), *c = make(3);
    a->next = b; b->prev = a; b->next = c; c->prev = b;
    for (struct Node *p = c; p; p = p->prev) printf("%d ", p->value);
    printf("\n");
    free(a); free(b); free(c);
    return 0;
}

La eliminación es más sencilla

Como cada nodo conoce a su predecesor, puede eliminarlo sin buscar el nodo anterior.

Solo tiene que conectar node->prev con node->next en ambas direcciones.

#include <stdio.h>
#include <stdlib.h>

struct Node { int value; struct Node *prev; struct Node *next; };
struct Node *make(int v){struct Node*n=malloc(sizeof*n);n->value=v;n->prev=NULL;n->next=NULL;return n;}

void del(struct Node **head, struct Node *n) {
    if (n->prev) n->prev->next = n->next; else *head = n->next;
    if (n->next) n->next->prev = n->prev;
    free(n);
}

int main(void) {
    struct Node *a = make(1), *b = make(2), *c = make(3);
    a->next=b; b->prev=a; b->next=c; c->prev=b;
    struct Node *head = a;
    del(&head, b);
    printf("%d %d\n", head->value, head->next->value);
    return 0;
}

Actualizar ambos vecinos

Al eliminar un nodo, corrija siempre el next del nodo anterior y el prev del nodo siguiente.

Compruebe si hay NULL en cada extremo para no desreferenciar un vecino inexistente.

#include <stdio.h>
#include <stdlib.h>

struct Node { int value; struct Node *prev; struct Node *next; };
struct Node *make(int v){struct Node*n=malloc(sizeof*n);n->value=v;n->prev=NULL;n->next=NULL;return n;}

int main(void) {
    struct Node *a = make(1), *b = make(2);
    a->next = b; b->prev = a;
    a->next = NULL;
    free(b);
    printf("now only %d remains\n", a->value);
    free(a);
    return 0;
}

Mantener un puntero tail

Muchas listas doblemente enlazadas también almacenan un puntero tail al último nodo, lo que permite añadir elementos al final en O(1) y recorrer la lista hacia atrás desde el final.

#include <stdio.h>
#include <stdlib.h>

struct Node { int value; struct Node *prev; struct Node *next; };
struct Node *make(int v){struct Node*n=malloc(sizeof*n);n->value=v;n->prev=NULL;n->next=NULL;return n;}

int main(void) {
    struct Node *head = make(1), *tail = head;
    struct Node *n = make(2);
    tail->next = n; n->prev = tail; tail = n;
    printf("tail = %d\n", tail->value);
    free(head); free(n);
    return 0;
}

Compromisos

Las listas doblemente enlazadas requieren memoria adicional (un puntero más por nodo) y obligan a actualizar dos enlaces en cada modificación.

A cambio, ofrecen recorrido bidireccional y eliminación en O(1) de un nodo conocido. Elija según sus necesidades.

#include <stdio.h>

int main(void) {
    printf("Singly: less memory, one-way\n");
    printf("Doubly: more memory, two-way + easy delete\n");
    return 0;
}

Comprobación rápida

Compruebe su comprensión de las listas doblemente enlazadas.

Resumen

Ha aprendido sobre las listas doblemente enlazadas:

  • Cada nodo tiene punteros prev y next.
  • Enlazar nodos requiere actualizar ambas direcciones.
  • Puede recorrer la lista hacia delante y hacia atrás, y eliminar un nodo conocido en O(1).
  • El coste es una mayor cantidad de memoria y más actualizaciones de punteros; un puntero tail permite añadir elementos al final en O(1).

Preguntas frecuentes

¿La lección «Listas doblemente enlazadas» es gratis?

Sí — el texto completo de «Listas doblemente enlazadas» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C Academy, actualiza a CoddyKit PRO. El curso de C Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Listas doblemente enlazadas»?

Enlaces bidireccionales Practicas C Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar C Academy?

No se requiere experiencia previa. C Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «Listas doblemente enlazadas»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de C Academy?

Sí. Cada lección de C Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Listas enlazadas simples
  2. Inserción y eliminación
  3. Recorrido y búsqueda
  4. Listas doblemente enlazadas
← Volver a C Academy