Resumen
Hasta aquí, cada colección del curso guardaba datos de un solo tipo: notas, estaturas, casillas de una tabla. Las entidades de un problema, en cambio, tienen varios rasgos de tipos distintos: un estudiante tiene un nombre y una nota; un libro, un título, un autor y un año. Esta clase presenta el registro, el tipo compuesto que define el propio programador con struct para agrupar esos rasgos bajo un solo nombre. Empieza por la razón de ser del registro, la fragilidad de los vectores paralelos; sigue con la definición de un struct, sus campos con valor inicial y la creación de registros con llaves y con inicializadores designados; después, los registros como parámetros y como resultados de funciones; los vectores de registros, que se recorren con ligaduras estructuradas y se ordenan y se buscan por un campo, con la cuestión del ordenamiento estable; y cierra con el arte de modelar un problema con tipos que reflejen su dominio.
Objetivos de aprendizaje
- Definir un
structcon campos y valores iniciales, y crear registros con inicialización con llaves, también con inicializadores designados. - Escribir funciones que reciban y devuelvan registros, eligiendo el modo de paso.
- Ordenar y buscar en un vector de registros por un campo con
std::ranges::sort,std::ranges::stable_sortystd::ranges::findcon una proyección, y distinguir un ordenamiento estable de uno que no lo es. - Modelar con registros los datos de un problema y justificar qué campos y tipos se eligen.
Agrupar datos
Vectores paralelos
Supóngase que un programa debe guardar, para cada estudiante de un grupo, su nombre, su nota y su edad. Con lo visto hasta la clase Tablas, la solución a mano son tres vectores, uno por rasgo, con el convenio de que el índice designa a la misma persona en los tres: names[i], grades[i] y ages[i]. Se llaman vectores paralelos. Una tabla no sirve, porque sus casillas deben ser todas del mismo tipo, y un nombre no es un número.
#include <algorithm>#include <cstddef>#include <print>#include <string>#include <vector>int main(){ const std::vector<std::string> names{"Ana", "Luis", "Eva"}; std::vector<int> grades{6, 4, 7}; const std::vector<int> ages{19, 22, 20}; std::ranges::sort(grades); for (std::size_t i{0}; i < names.size(); ++i) { std::println("{}: nota {}, {} años", names[i], grades[i], ages[i]); }}Ana: nota 4, 19 añosLuis: nota 6, 22 añosEva: nota 7, 20 añosEl programa quería ordenar a los estudiantes por nota, y ordenó solo las notas. Compila sin avisos y no falla en ningún detector; sin embargo, su salida es falsa: Ana tenía un 6 y figura con un 4. El convenio que unía los tres vectores no está escrito en ningún lugar que el compilador pueda leer, de modo que nada impide romperlo. De ello se sigue la fragilidad de los vectores paralelos: toda operación que mueva, añada o quite un elemento debe repetirse, igual y en el mismo orden, en todos ellos; y basta olvidar uno para corromper los datos en silencio.
Tres vectores paralelos frente a un vector de fichas, cada una con los tres datos de una persona.
Demostración
La columna 0 describe a una persona:
names[0],grades[0]yages[0]son el nombre, la nota y la edad de Ana. El vínculo es solo el índice.std::ranges::sort(grades)reordena una sola fila. Las otras dos no se enteran: la columna 0 junta ahora el nombre de Ana, la nota de Luis y la edad de Ana, que no son de nadie.La alternativa: un solo vector, cuyos elementos son fichas. Cada ficha contiene los tres datos de una persona, y el vínculo entre ellos ya no es un convenio sobre índices, sino la ficha misma.
Ordenar por nota mueve fichas enteras: la de Luis pasa al primer lugar con su nombre y su edad. Ningún dato puede separarse de los demás, porque la operación no los ve por separado.
Si esto es así, lo que el problema pide es un tipo cuyos valores sean fichas: un valor que contenga un nombre, una nota y una edad, y que se copie, se pase a una función, se guarde en un vector y se ordene como un todo. C++ no lo trae hecho, porque las fichas de cada problema son distintas; pero permite que el programador lo defina. Ese tipo es el registro.
Cargando el contenido…