12 - Proyecto final: lista simplemente enlazada

12.1 Implementar una lista completa

En este proyecto construimos una lista simplemente enlazada con operaciones de inserción, eliminación, búsqueda y limpieza. Los archivos están separados para facilitar la compilación y depuración en CLion.

12.2 Archivo list.h

/* list.h */
#ifndef LIST_H
#define LIST_H
#include <stdbool.h>

typedef struct Nodo {
  int valor;
  struct Nodo *sig;
} Nodo;

typedef struct {
  Nodo *cabeza;
} Lista;

void lista_inicializar(Lista *lista);
bool lista_insertar_inicio(Lista *lista, int valor);
bool lista_insertar_final(Lista *lista, int valor);
bool lista_eliminar_valor(Lista *lista, int valor);
Nodo *lista_buscar(const Lista *lista, int valor);
void lista_imprimir(const Lista *lista);
void lista_limpiar(Lista *lista);

#endif

12.3 Archivo list.c

/* list.c */
#include "list.h"
#include <stdio.h>
#include <stdlib.h>

void lista_inicializar(Lista *lista) {
  lista->cabeza = NULL;
}

bool lista_insertar_inicio(Lista *lista, int valor) {
  Nodo *n = malloc(sizeof(Nodo));
  if (!n) return false;
  n->valor = valor;
  n->sig = lista->cabeza;
  lista->cabeza = n;
  return true;
}

bool lista_insertar_final(Lista *lista, int valor) {
  Nodo *n = malloc(sizeof(Nodo));
  if (!n) return false;
  n->valor = valor;
  n->sig = NULL;
  if (!lista->cabeza) {
    lista->cabeza = n;
    return true;
  }
  Nodo *reco = lista->cabeza;
  while (reco->sig) {
    reco = reco->sig;
  }
  reco->sig = n;
  return true;
}

bool lista_eliminar_valor(Lista *lista, int valor) {
  if (!lista->cabeza) return false;
  if (lista->cabeza->valor == valor) {
    Nodo *victima = lista->cabeza;
    lista->cabeza = victima->sig;
    free(victima);
    return true;
  }
  Nodo *reco = lista->cabeza;
  while (reco->sig && reco->sig->valor != valor) {
    reco = reco->sig;
  }
  if (!reco->sig) return false;
  Nodo *victima = reco->sig;
  reco->sig = victima->sig;
  free(victima);
  return true;
}

Nodo *lista_buscar(const Lista *lista, int valor) {
  const Nodo *reco = lista->cabeza;
  while (reco) {
    if (reco->valor == valor) {
      return (Nodo *)reco;
    }
    reco = reco->sig;
  }
  return NULL;
}

void lista_imprimir(const Lista *lista) {
  const Nodo *reco = lista->cabeza;
  while (reco) {
    printf("%d -> ", reco->valor);
    reco = reco->sig;
  }
  puts("NULL");
}

void lista_limpiar(Lista *lista) {
  Nodo *reco = lista->cabeza;
  while (reco) {
    Nodo *tmp = reco->sig;
    free(reco);
    reco = tmp;
  }
  lista->cabeza = NULL;
}

12.4 Archivo main.c para pruebas

/* main.c */
#include "list.h"
#include <stdio.h>

int main(void) {
  Lista lista;
  lista_inicializar(&lista);
  lista_insertar_inicio(&lista, 10);
  lista_insertar_final(&lista, 20);
  lista_insertar_final(&lista, 30);
  lista_imprimir(&lista);

  Nodo *n = lista_buscar(&lista, 20);
  if (n) {
    printf("Encontrado: %d\n", n->valor);
  }

  lista_eliminar_valor(&lista, 10);
  lista_imprimir(&lista);
  lista_limpiar(&lista);
  return 0;
}

12.5 Probar en CLion

Pasos sugeridos:

  • Crear un nuevo proyecto de consola.
  • Añadir los archivos list.h, list.c y main.c.
  • Configurar las opciones de compilación (C11 / C99).
  • Ejecutar en modo Debug para inspeccionar punteros.
Depuración de punteros en CLion