11 - Ejemplo práctico 2: simulador de historial

11.1 Escenario del problema

Queremos recrear el comportamiento de un navegador: visitar URLs, volver atrás y adelante, y registrar el historial sin perder contexto. La solución emplea dos pilas para representar los movimientos de navegación.

11.2 Modelado con pilas

Mantenemos dos estructuras:

  • Pila Back: almacena las páginas visitadas en orden cronológico.
  • Pila Forward: guarda los destinos a los que se puede regresar tras usar "Atrás".

Visitar una nueva URL limpia la pila Forward (como en un navegador real) y apila la URL en Back.

11.3 Operaciones requeridas

  1. Visit: recibe una URL, la apila en Back y vacía Forward.
  2. Back: desapila el tope de Back, lo inserta en Forward y retorna la nueva página actual.
  3. Forward: desapila el tope de Forward, lo apila en Back y retorna la URL correspondiente.
  4. Print: muestra ambas pilas para depurar (top indica la página actual).

11.4 Casos especiales

  • Si Back tiene un solo elemento, no se puede ir más atrás.
  • Si Forward está vacía, la acción "Adelante" no debe modificar el estado.
  • Se puede limitar el tamaño de Back para simular historial acotado.
  • Los comandos deben ignorar URL vacías o repetidas consecutivas (opcional).

11.5 Implementación en C

Utilizaremos pilas dinámicas para no restringir el tamaño. A continuación un prototipo sencillo:

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

typedef struct Nodo {
  char *url;
  struct Nodo *sig;
} Nodo;

typedef struct {
  Nodo *top;
} PilaURL;

static void pila_init(PilaURL *p) { p->top = NULL; }
static int pila_is_empty(const PilaURL *p) { return p->top == NULL; }

static void pila_push(PilaURL *p, const char *url) {
  Nodo *n = malloc(sizeof(Nodo));
  if (!n) return;
  n->url = strdup(url);
  n->sig = p->top;
  p->top = n;
}

static char *pila_pop(PilaURL *p) {
  if (pila_is_empty(p)) return NULL;
  Nodo *tmp = p->top;
  char *valor = tmp->url;
  p->top = tmp->sig;
  free(tmp);
  return valor;
}

static void pila_clear(PilaURL *p) {
  while (!pila_is_empty(p)) {
    free(pila_pop(p));
  }
}

static void pila_print(const PilaURL *p, const char *nombre) {
  printf("%s:\n", nombre);
  for (Nodo *n = p->top; n; n = n->sig) {
    printf("  %s%s\n", n->url, n == p->top ? " <- top" : "");
  }
}

typedef struct {
  PilaURL back;
  PilaURL forward;
  char *actual;
} Historial;

void historial_init(Historial *h, const char *home) {
  pila_init(&h->back);
  pila_init(&h->forward);
  h->actual = strdup(home);
  pila_push(&h->back, home);
}

void historial_visit(Historial *h, const char *url) {
  pila_push(&h->back, url);
  pila_clear(&h->forward);
  free(h->actual);
  h->actual = strdup(url);
}

const char *historial_back(Historial *h) {
  if (!h->back.top || !h->back.top->sig) return h->actual;
  char *prev = pila_pop(&h->back);
  pila_push(&h->forward, prev);
  free(prev);
  free(h->actual);
  h->actual = strdup(h->back.top->url);
  return h->actual;
}

const char *historial_forward(Historial *h) {
  if (pila_is_empty(&h->forward)) return h->actual;
  char *next = pila_pop(&h->forward);
  pila_push(&h->back, next);
  free(h->actual);
  h->actual = strdup(next);
  free(next);
  return h->actual;
}

void historial_print(const Historial *h) {
  printf("Pagina actual: %s\n", h->actual);
  pila_print(&h->back, "BACK");
  pila_print(&h->forward, "FORWARD");
}

void historial_clear(Historial *h) {
  pila_clear(&h->back);
  pila_clear(&h->forward);
  free(h->actual);
}

int main(void) {
  Historial hist;
  historial_init(&hist, "https://inicio.com");
  historial_visit(&hist, "https://noticias.com");
  historial_visit(&hist, "https://docs.com");
  historial_back(&hist);
  historial_forward(&hist);
  historial_visit(&hist, "https://foros.com");
  historial_print(&hist);
  historial_clear(&hist);
  return 0;
}

El programa permite probar visitas, retrocesos y avances, mostrando cómo se actualizan ambas pilas.

11.6 Relación con entrevistas técnicas

Este ejemplo combina pilas, manejo de cadenas y estructuras auxiliares, todo muy frecuente en preguntas de diseño de sistemas. Extensiones comunes:

  • Persistir el historial en disco.
  • Contar visitas por dominio o categoría.