Atlasingeniería

Algoritmos y programaciónFundamentosTema 1

Qué es un algoritmo de verdad

Un algoritmo es una secuencia finita y precisa que transforma entradas en salidas. Para evaluarlo hay que separar especificación, corrección y eficiencia.

Una receta ambigua puede servirle a una persona; una computadora necesita pasos que no dejen lugar a interpretación. Un algoritmo es esa estrategia precisa, independiente del lenguaje en el que después la programemos.

Entradas válidas y una especificación de salida

Un algoritmo recibe entradas válidas y debe producir una salida que cumpla una especificación. Para buscar un número, la entrada puede ser un arreglo y un objetivo; la salida, su posición o una señal de ausencia.

Las precondiciones dicen qué entradas acepta. Las postcondiciones describen qué garantiza al terminar. Sin ese contrato no podemos distinguir un resultado correcto de uno que sólo parece razonable en algunos ejemplos.

Precondición: el arreglo está ordenado. Postcondición: devuelve la posición del valor, o −1 si no está. Buscamos el 7.

1 / 8
La segunda corrida no se cuelga ni tira ningún error: devuelve «no está» sobre un arreglo donde el valor estaba. Eso es lo que pasa cuando se rompe una precondición, y es el motivo por el que el contrato tiene que estar escrito: sin él, no hay forma de decidir si el algoritmo se portó mal o lo usamos mal.

Antes de seguir, predecí

Un procedimiento que para algunas entradas nunca termina, ¿es un algoritmo?

Definido, ejecutable y finito

Los pasos deben ser definidos, ejecutables y finitos. “Elegí una buena opción” no es una instrucción precisa si no explica cómo reconocerla. Repetir hasta encontrar una respuesta no es finito si algunas entradas jamás la producen.

Un mismo problema admite muchos algoritmos. Ordenar por inserción, mezcla o partición persigue la misma postcondición mediante estrategias y costos diferentes.

Trazar a mano: normal, mínimo y borde

Trazar consiste en ejecutar el algoritmo a mano y registrar cómo cambia su estado. Conviene usar un caso normal, uno mínimo y uno de borde. Una traza encuentra errores concretos, pero no demuestra corrección para todas las entradas.

La demostración explica por qué cada paso conserva una propiedad útil y por qué al terminar esa propiedad implica la postcondición. Los tests dan evidencia; el razonamiento cubre la familia completa de casos.

Escena 1 — Una traza completa, paso por paso

paso a paso

Cargando la escena…

Cambiá la cantidad de elementos para trazar el caso mínimo —una lista de uno, donde el ciclo no se ejecuta— y el caso con empate, donde la comparación estricta decide cuál de los dos máximos gana. Eso es lo que una especificación tiene que dejar dicho.

Correctos los dos, y muy distintos

Dos algoritmos correctos pueden comportarse de manera muy distinta cuando crece la entrada. Medimos tiempo, memoria y a veces accesos a red o disco. La complejidad describe el crecimiento; la medición captura constantes, runtime y hardware.

Primero debe ser correcto. Después comparamos recursos dentro del contexto real: tamaño de datos, frecuencia, límites y claridad de mantenimiento.

El mismo problema, dos algoritmos

// Problema: ¿hay dos elementos que sumen exactamente target?
// Precondición: values son enteros. Postcondición: true si existe el par.

// Algoritmo 1: probar todos los pares. O(n²) tiempo, O(1) memoria.
const hasPairBrute = (values: readonly number[], target: number): boolean => {
  for (let i = 0; i < values.length; i += 1) {
    for (let j = i + 1; j < values.length; j += 1) {
      if (values[i]! + values[j]! === target) return true;
    }
  }
  return false;
};

// Algoritmo 2: recordar lo visto. O(n) tiempo, O(n) memoria.
const hasPairSeen = (values: readonly number[], target: number): boolean => {
  const seen = new Set<number>();
  for (const value of values) {
    if (seen.has(target - value)) return true; // el complemento ya pasó
    seen.add(value);
  }
  return false;
};

Los dos cumplen el mismo contrato y son algoritmos distintos: uno prueba todas las combinaciones y el otro cambia memoria por tiempo. Esa es la decisión que hay detrás de casi todos los pares de algoritmos que resuelven lo mismo.

El segundo tiene además un detalle que se escapa: el orden importa. Preguntar por el complemento antes de agregar el valor actual es lo que impide que un elemento se empareje consigo mismo cuando target es su doble. Cambiar esas dos líneas de orden produce un algoritmo que anda casi siempre, y ése «casi» es lo que separa un procedimiento de uno correcto.

Del algoritmo al programa

AlgoritmoPrograma
Qué esun procedimiento, independiente del lenguajeuna implementación concreta
Se analiza concomplejidad, correctitudperfilado, medición
Falla porestar mal pensadoun borde, un tipo, un recurso
Se comunica conpseudocódigo o palabrascódigo que compila
Termina cuandoestá demostradopasa los tests y corre en producción
Separar las dos cosas evita las dos confusiones habituales: creer que un programa que anda implica un algoritmo correcto, y creer que un algoritmo correcto implica un programa que anda.

Lo que preguntan sobre esto

Cierre

Un algoritmo no es código ni una idea vaga. Es un procedimiento finito con entradas, pasos y garantías observables. Especificar, justificar y medir son tres preguntas distintas; juntas permiten pasar de “funcionó una vez” a una solución confiable.

Autoevaluación

¿Lo entendiste?

«Elegí una buena opción». ¿Por qué no es un paso de un algoritmo?
¿Para qué sirven precondiciones y postcondiciones?
Trazar el algoritmo a mano con tres casos, ¿qué prueba?
¿Qué va primero, correcto o eficiente?