Estructuras de Datosc++arreglosvectoresarraysvector

Arreglos y Vectores

Aprende a almacenar colecciones de datos usando arreglos y vectores en C++

OOI Oaxaca9 de febrero de 20267 min read

¿Qué es un arreglo?

Imagina que tienes 100 estudiantes y quieres guardar la calificación de cada uno. Sin arreglos, necesitarías 100 variables: cal1, cal2, cal3, ..., cal100. ¡Imposible de manejar!

Un arreglo es una colección de variables del mismo tipo, todas agrupadas bajo un mismo nombre. Es como un edificio de departamentos: un solo edificio con muchos departamentos numerados, y cada departamento guarda un valor.

Arreglo "calificaciones":
┌──────┬──────┬──────┬──────┬──────┐
│  85  │  92  │  78  │  95  │  88  │
├──────┼──────┼──────┼──────┼──────┤
│ [0]  │ [1]  │ [2]  │ [3]  │ [4]  │  ← Índices
└──────┴──────┴──────┴──────┴──────┘

Arreglos estáticos (de C)

Declaración

int calificaciones[5];          // Arreglo de 5 enteros (sin inicializar)
int numeros[5] = {10, 20, 30, 40, 50};  // Inicializado con valores
int ceros[100] = {0};           // Todos inicializados a 0
int masNumeros[] = {1, 2, 3};   // El tamaño se deduce (3 elementos)

Acceso por índice

Los índices empiezan en 0 (no en 1):

int arr[5] = {10, 20, 30, 40, 50};

cout << arr[0] << endl;   // 10 (primer elemento)
cout << arr[1] << endl;   // 20 (segundo elemento)
cout << arr[4] << endl;   // 50 (último elemento)

arr[2] = 99;              // Cambiar el tercer elemento
cout << arr[2] << endl;   // 99
⚠️

¡Los índices empiezan en 0! Un arreglo de tamaño n tiene índices del 0 al n-1. Acceder a arr[n] o arr[-1] es un error grave (undefined behavior) que puede causar resultados impredecibles o que tu programa se cierre.

Recorrer un arreglo

int arr[5] = {10, 20, 30, 40, 50};
int n = 5;

// Imprimir todos los elementos
for (int i = 0; i < n; i++) {
    cout << arr[i] << " ";
}
cout << endl;
// Salida: 10 20 30 40 50

Leer un arreglo

int n;
cin >> n;

int arr[100001];  // Declarar con tamaño máximo posible
for (int i = 0; i < n; i++) {
    cin >> arr[i];
}

Arreglos globales vs locales

// Global: se inicializa automáticamente a 0, puede ser muy grande
int arrGlobal[1000001];

int main() {
    // Local: NO se inicializa (basura), tamaño limitado (~1MB de stack)
    int arrLocal[1000001];  // ⚠️ Puede causar stack overflow

    return 0;
}
💡

En competencias, declara arreglos grandes como variables globales. Las variables locales viven en el "stack" que tiene un tamaño limitado (~1-8 MB). Las globales viven en un segmento diferente sin ese límite.

Vectores (la versión moderna y flexible)

Un vector es como un arreglo, pero puede cambiar de tamaño. Es la estructura de datos más usada en C++ competitivo.

Incluir la biblioteca

#include <vector>
// O simplemente #include <bits/stdc++.h>

Crear vectores

vector<int> v;                    // Vector vacío de enteros
vector<int> v(5);                 // Vector de 5 elementos (todos en 0)
vector<int> v(5, -1);             // Vector de 5 elementos, todos valen -1
vector<int> v = {10, 20, 30};     // Vector con valores iniciales
vector<string> nombres;           // Vector de strings
vector<double> decimales(100, 0.0); // 100 elementos, todos 0.0

Operaciones básicas

vector<int> v;

// Agregar elementos al final
v.push_back(10);    // v = {10}
v.push_back(20);    // v = {20}
v.push_back(30);    // v = {10, 20, 30}

// Tamaño
cout << v.size() << endl;  // 3

// Acceder por índice (igual que arreglos)
cout << v[0] << endl;      // 10
cout << v[1] << endl;      // 20
v[2] = 99;                 // Cambiar un elemento

// Último elemento
cout << v.back() << endl;  // 99

// Primer elemento
cout << v.front() << endl; // 10

// Eliminar el último elemento
v.pop_back();               // v = {10, 20}

// ¿Está vacío?
cout << v.empty() << endl;  // 0 (false, no está vacío)

// Limpiar todo
v.clear();                   // v = {} (vacío)
cout << v.empty() << endl;  // 1 (true)

Recorrer un vector

vector<int> v = {10, 20, 30, 40, 50};

// Forma 1: con índice
for (int i = 0; i < v.size(); i++) {
    cout << v[i] << " ";
}

// Forma 2: for-each (más elegante)
for (int x : v) {
    cout << x << " ";
}

// Forma 3: for-each por referencia (si quieres modificar)
for (int &x : v) {
    x *= 2;  // Duplica cada elemento
}

Leer un vector

int n;
cin >> n;

vector<int> v(n);
for (int i = 0; i < n; i++) {
    cin >> v[i];
}

Arreglos vs Vectores

CaracterísticaArregloVector
TamañoFijo al declararPuede crecer/reducir
Saber el tamañoDebes recordar nv.size()
Agregar elementosNo se puedepush_back()
InicializaciónManual o parcialAutomática
VelocidadLigeramente más rápidoCasi igual

En competencias, la mayoría de los programadores usan vectores por su flexibilidad.

Operaciones comunes en competencias

Sumar todos los elementos

vector<int> v = {3, 1, 4, 1, 5};
int suma = 0;
for (int x : v) {
    suma += x;
}
cout << suma << endl;  // 14

Encontrar máximo y mínimo

vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};

int maximo = *max_element(v.begin(), v.end());
int minimo = *min_element(v.begin(), v.end());

cout << "Max: " << maximo << ", Min: " << minimo << endl;
// Max: 9, Min: 1

Ordenar

vector<int> v = {5, 2, 8, 1, 9, 3};

sort(v.begin(), v.end());     // Orden ascendente: 1 2 3 5 8 9

sort(v.rbegin(), v.rend());   // Orden descendente: 9 8 5 3 2 1

Invertir

vector<int> v = {1, 2, 3, 4, 5};
reverse(v.begin(), v.end());
// v = {5, 4, 3, 2, 1}

Eliminar duplicados

vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3};
sort(v.begin(), v.end());                       // Primero ordenar
v.erase(unique(v.begin(), v.end()), v.end());   // Eliminar duplicados
// v = {1, 2, 3, 4, 5, 6, 9}

Buscar un elemento

vector<int> v = {10, 20, 30, 40, 50};

// Buscar si existe
auto it = find(v.begin(), v.end(), 30);
if (it != v.end()) {
    cout << "Encontrado en posición " << (it - v.begin()) << endl;
} else {
    cout << "No encontrado" << endl;
}

Vectores 2D (matrices con vectores)

// Crear una matriz de 3x4 llena de ceros
int filas = 3, cols = 4;
vector<vector<int>> matriz(filas, vector<int>(cols, 0));

// Acceder
matriz[0][0] = 1;
matriz[1][2] = 5;

// Recorrer
for (int i = 0; i < filas; i++) {
    for (int j = 0; j < cols; j++) {
        cout << matriz[i][j] << " ";
    }
    cout << endl;
}

Arreglo de frecuencias

Un patrón extremadamente común: contar cuántas veces aparece cada valor.

int n;
cin >> n;

vector<int> v(n);
for (int i = 0; i < n; i++) cin >> v[i];

// Si los valores van de 0 a MAX
int freq[100001] = {0};
for (int x : v) {
    freq[x]++;
}

// ¿Cuántas veces aparece el 5?
cout << freq[5] << endl;

Ejercicio de práctica

Lee N números. Imprime cuántos son mayores que el promedio.

Entrada:

5
10 20 30 40 50

Salida: 3 (el promedio es 30, y 30 no es "mayor que" 30, pero 40 y 50 sí... ¡espera! Veamos: promedio = 30. Mayores estrictos que 30: 40 y 50. Son 2.)

Ver solución
#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n;
    cin >> n;

    vector<int> v(n);
    double suma = 0;
    for (int i = 0; i < n; i++) {
        cin >> v[i];
        suma += v[i];
    }

    double promedio = suma / n;
    int cuenta = 0;
    for (int x : v) {
        if (x > promedio) {
            cuenta++;
        }
    }

    cout << cuenta << endl;

    return 0;
}

Nota: Necesitamos guardar todos los valores en un vector porque primero debemos calcular el promedio (recorremos una vez) y luego contar cuántos lo superan (recorremos de nuevo).

Siguiente paso

Aprende sobre Strings para manipular texto de forma poderosa en C++.