12 - Ejemplo práctico: ranking de jugadores

Los torneos en línea necesitan ordenar jugadores según su puntaje para mostrar tablas de posiciones, detectar empates y seleccionar rivales. Un árbol binario de búsqueda permite insertar nuevos resultados sin procesar toda la tabla, consultar un jugador por su puntaje y generar reportes ordenados al instante.

12.1 Enunciado

Registrar en un ABB las puntuaciones:

  • Ana → 1800
  • Bruno → 1650
  • Carla → 2050
  • Diego → 1500
  • Elena → 1900
  • Facundo → 2100

El sistema debe:

  1. Permitir la inserción de nuevos puntajes.
  2. Buscar un jugador para ver su puntaje.
  3. Listar a los jugadores en orden descendente para la tabla final.

12.2 Modelo de nodo

Incluye el nombre y el puntaje. Utilizamos cadenas cortas (hasta 31 caracteres más terminador).

typedef struct PlayerNode {
  char nombre[32];
  int puntaje;
  struct PlayerNode *izquierdo;
  struct PlayerNode *derecho;
} PlayerNode;

12.3 Inserción

El orden del árbol se basa en el puntaje. Si dos jugadores empatan, los ubicamos en la rama derecha para mantener consistencia.

PlayerNode *crearJugador(const char *nombre, int puntaje) {
  PlayerNode *n = malloc(sizeof(PlayerNode));
  if (!n) return NULL;
  strncpy(n->nombre, nombre, sizeof(n->nombre) - 1);
  n->nombre[sizeof(n->nombre) - 1] = '\0';
  n->puntaje = puntaje;
  n->izquierdo = NULL;
  n->derecho = NULL;
  return n;
}

PlayerNode *insertarJugador(PlayerNode *raiz, const char *nombre, int puntaje) {
  if (!raiz) return crearJugador(nombre, puntaje);
  if (puntaje < raiz->puntaje) {
    raiz->izquierdo = insertarJugador(raiz->izquierdo, nombre, puntaje);
  } else {
    raiz->derecho = insertarJugador(raiz->derecho, nombre, puntaje);
  }
  return raiz;
}

12.4 Búsqueda por puntaje

La consulta retorna el nodo del jugador o NULL si el puntaje no existe.

PlayerNode *buscarPorPuntaje(PlayerNode *raiz, int puntaje) {
  if (!raiz) return NULL;
  if (puntaje == raiz->puntaje) return raiz;
  return (puntaje < raiz->puntaje)
      ? buscarPorPuntaje(raiz->izquierdo, puntaje)
      : buscarPorPuntaje(raiz->derecho, puntaje);
}

12.5 Tabla descendente

Un recorrido postorden invertido (derecha, nodo, izquierda) genera la tabla de mayor a menor puntaje.

void imprimirTablaDesc(PlayerNode *raiz) {
  if (!raiz) return;
  imprimirTablaDesc(raiz->derecho);
  printf("%s - %d\n", raiz->nombre, raiz->puntaje);
  imprimirTablaDesc(raiz->izquierdo);
}

12.6 Verificación

  • Agrega un jugador con puntaje repetido para validar que se ubique en la rama derecha.
  • Busca un puntaje inexistente y comprueba que el resultado es NULL.
  • Imprime la tabla y confirma que el primer nombre sea el de mayor puntaje.

12.7 Código completo para CLion

Programa que arma el ranking, muestra la tabla y consulta un puntaje.

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

typedef struct PlayerNode {
  char nombre[32];
  int puntaje;
  struct PlayerNode *izquierdo;
  struct PlayerNode *derecho;
} PlayerNode;

PlayerNode *crearJugador(const char *nombre, int puntaje) {
  PlayerNode *n = malloc(sizeof(PlayerNode));
  if (!n) return NULL;
  strncpy(n->nombre, nombre, sizeof(n->nombre) - 1);
  n->nombre[sizeof(n->nombre) - 1] = '\0';
  n->puntaje = puntaje;
  n->izquierdo = NULL;
  n->derecho = NULL;
  return n;
}

PlayerNode *insertarJugador(PlayerNode *raiz, const char *nombre, int puntaje) {
  if (!raiz) return crearJugador(nombre, puntaje);
  if (puntaje < raiz->puntaje) {
    raiz->izquierdo = insertarJugador(raiz->izquierdo, nombre, puntaje);
  } else {
    raiz->derecho = insertarJugador(raiz->derecho, nombre, puntaje);
  }
  return raiz;
}

PlayerNode *buscarPorPuntaje(PlayerNode *raiz, int puntaje) {
  if (!raiz) return NULL;
  if (puntaje == raiz->puntaje) return raiz;
  return (puntaje < raiz->puntaje)
      ? buscarPorPuntaje(raiz->izquierdo, puntaje)
      : buscarPorPuntaje(raiz->derecho, puntaje);
}

void imprimirTablaDesc(PlayerNode *raiz) {
  if (!raiz) return;
  imprimirTablaDesc(raiz->derecho);
  printf("%s - %d\n", raiz->nombre, raiz->puntaje);
  imprimirTablaDesc(raiz->izquierdo);
}

void liberar(PlayerNode *raiz) {
  if (!raiz) return;
  liberar(raiz->izquierdo);
  liberar(raiz->derecho);
  free(raiz);
}

int main(void) {
  PlayerNode *ranking = NULL;
  ranking = insertarJugador(ranking, "Ana", 1800);
  ranking = insertarJugador(ranking, "Bruno", 1650);
  ranking = insertarJugador(ranking, "Carla", 2050);
  ranking = insertarJugador(ranking, "Diego", 1500);
  ranking = insertarJugador(ranking, "Elena", 1900);
  ranking = insertarJugador(ranking, "Facundo", 2100);
  ranking = insertarJugador(ranking, "Gael", 1900); /* puntaje repetido */

  puts("Tabla descendente:");
  imprimirTablaDesc(ranking);

  int consulta = 1900;
  PlayerNode *jugador = buscarPorPuntaje(ranking, consulta);
  if (jugador) {
    printf("\nPrimer jugador con %d puntos: %s\n", consulta, jugador->nombre);
  } else {
    printf("\nNo hay jugadores con %d puntos\n", consulta);
  }

  liberar(ranking);
  return 0;
}