Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Ejercicios de Análisis de Complejidad Algorítmica

Universidad Nacional de Río Negro

Acerca de

Estos ejercicios tienen como fin practicar el análisis asintótico de algoritmos, el uso de las notaciones Big-O, Omega y Theta, y el cálculo formal e informal del costo temporal y espacial de subprogramas iterativos y recursivos en C.

Capítulos de Apunte Correspondientes

Cuestiones de Estilo Aplicables


Fundamentos de Notación Asintótica

Ejercicio 24.1 - Simplificación de Funciones ⭐⭐☆☆☆

Para cada función de costo, determinar su clasificación en notación Big-O (ignorando constantes y términos de menor orden): a) T(n)=5n3+2n2+100T(n) = 5n^3 + 2n^2 + 100
b) T(n)=3nlogn+2n+50T(n) = 3n \log n + 2n + 50
c) T(n)=2n+n3+1000nT(n) = 2^n + n^3 + 1000n
d) T(n)=log(n2)+nT(n) = \log(n^2) + \sqrt{n}
e) T(n)=n!+2n+n10T(n) = n! + 2^n + n^{10}

Ejercicio 24.2 - Comparación de Funciones ⭐⭐☆☆☆

Ordenar las siguientes funciones de menor a mayor tasa de crecimiento asintótico:

logn,n2,2n,n!,nlogn,n,n3,1,nlog2n,22n\log n, \quad n^2, \quad 2^n, \quad n!, \quad n \log n, \quad \sqrt{n}, \quad n^3, \quad 1, \quad n \log^2 n, \quad 2^{2n}

Ejercicio 24.3 - Verdadero o Falso ⭐⭐☆☆☆

Determinar si las siguientes afirmaciones son verdaderas o falsas. Justificar. a) n2+n=O(n2)n^2 + n = O(n^2)
b) n2=O(n3)n^2 = O(n^3)
c) n3=O(n2)n^3 = O(n^2)
d) 2n=O(3n)2^n = O(3^n)
e) 3n=O(2n)3^n = O(2^n)
f) log2n=O(log10n)\log_2 n = O(\log_{10} n)
g) nlogn=O(n2)n \log n = O(n^2)
h) n2=Ω(nlogn)n^2 = \Omega(n \log n)

Ejercicio 24.4 - Demostración Formal de Big-O ⭐⭐☆☆☆

Demostrar formalmente que f(n)=3n2+5n+2f(n) = 3n^2 + 5n + 2 es O(n2)O(n^2) encontrando constantes cc y n0n_0 que satisfagan la definición.


Análisis de Lazos Simples

Ejercicio 24.5 - Lazo Simple ⭐☆☆☆☆

Analizar la complejidad temporal de este código:

int suma = 0;
for (int i = 0; i < n; i++) {
    suma += i;
}

Ejercicio 24.6 - Lazo con Incremento Variable ⭐⭐☆☆☆

Analizar la complejidad de:

int suma = 0;
for (int i = 0; i < n; i += 2) {
    suma += i;
}

Ejercicio 24.7 - Lazo con Multiplicación ⭐⭐☆☆☆

Analizar la complejidad de:

int contador = 0;
for (int i = 1; i < n; i *= 2) {
    contador++;
}

Ejercicio 24.8 - Lazo con División ⭐⭐☆☆☆

Analizar la complejidad de:

int contador = 0;
for (int i = n; i > 1; i /= 2) {
    contador++;
}

Ejercicio 24.9 - Contar Operaciones ⭐☆☆☆☆

Contá cuántas operaciones ejecuta este código:

int suma = 0;
for (int i = 0; i < n; i++) {
    suma += i;
}

Orientación:


Ejercicio 24.10 - Analizar Lazo Anidado ⭐⭐☆☆☆

¿Cuál es la complejidad de este código?

for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
        printf("%d,%d ", i, j);
    }
}

Orientación:


Ejercicio 24.11 - Comparar Algoritmos ⭐⭐☆☆☆

Compará la complejidad de buscar un elemento en:

Orientación:


Ejercicio 24.12 - Identificar Complejidad ⭐⭐☆☆☆

Determiná la complejidad de cada fragmento:

a)

int suma = 0;
for (int i = 0; i < 100; i++) {
    suma += i;
}

b)

for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
        printf("%d ", i * j);
    }
}

c)

int i = n;
while (i > 0) {
    printf("%d ", i);
    i = i / 2;
}

Orientación:


Ejercicio 24.13 - Suma de Matriz ⭐⭐⭐☆☆

Analizá la complejidad de sumar todos los elementos de una matriz n×m.

Orientación:

1
2
3
4
5
6
int suma = 0;
for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
        suma += matriz[i][j];
    }
}

Ejercicio 24.14 - Fibonacci Naive vs Optimizado ⭐⭐⭐☆☆

Compará complejidad de Fibonacci recursivo vs iterativo.

Orientación:


Ejercicio 24.15 - Búsqueda del Máximo ⭐⭐☆☆☆

Implementá función para encontrar el máximo de un array y analizá su complejidad.

Orientación:

1
2
3
4
5
6
7
int maximo(int arr[], int n) {
    int max = arr[0];
    for (int i = 1; i < n; i++) {
        if (arr[i] > max) max = arr[i];
    }
    return max;
}

Ejercicio 24.16 - Duplicados en Array ⭐⭐⭐☆☆

Compará dos formas de encontrar duplicados:

Método 1: Comparar cada par

1
2
3
4
5
6
7
8
bool tiene_duplicados_1(int arr[], int n) {
    for (int i = 0; i < n; i++) {
        for (int j = i+1; j < n; j++) {
            if (arr[i] == arr[j]) return true;
        }
    }
    return false;
}

Método 2: Ordenar primero

1
2
3
4
5
6
7
bool tiene_duplicados_2(int arr[], int n) {
    qsort(arr, n, sizeof(int), comparar);  // O(n log n)
    for (int i = 0; i < n-1; i++) {
        if (arr[i] == arr[i+1]) return true;
    }
    return false;
}

Orientación:


Ejercicio 24.17 - Ordenamiento Burbuja ⭐⭐⭐☆☆

Analizá complejidad del ordenamiento burbuja.

Orientación:

1
2
3
4
5
6
7
8
9
void burbuja(int arr[], int n) {
    for (int i = 0; i < n-1; i++) {
        for (int j = 0; j < n-i-1; j++) {
            if (arr[j] > arr[j+1]) {
                intercambiar(&arr[j], &arr[j+1]);
            }
        }
    }
}

Ejercicio 24.18 - Complejidad Espacial ⭐⭐⭐☆☆

Analizá memoria usada por MergeSort.

Orientación:

1
2
3
4
5
6
7
8
void merge_sort(int arr[], int l, int r) {
    if (l < r) {
        int m = l + (r - l) / 2;
        merge_sort(arr, l, m);
        merge_sort(arr, m+1, r);
        merge(arr, l, m, r);  // Usa array temporal
    }
}

Ejercicio 24.19 - Suma de Pares ⭐⭐⭐⭐☆

Encontrá dos números en array que sumen un objetivo.

Método 1: Fuerza bruta

1
2
3
4
5
6
7
8
bool suma_objetivo_1(int arr[], int n, int objetivo) {
    for (int i = 0; i < n; i++) {
        for (int j = i+1; j < n; j++) {
            if (arr[i] + arr[j] == objetivo) return true;
        }
    }
    return false;
}

Método 2: Con tabla hash

1
2
3
4
5
6
7
8
9
10
bool suma_objetivo_2(int arr[], int n, int objetivo) {
    hash_set_t *set = crear_set();
    for (int i = 0; i < n; i++) {
        if (contiene(set, objetivo - arr[i])) {
            return true;
        }
        insertar(set, arr[i]);
    }
    return false;
}

Orientación:


Ejercicio 24.20 - Números Primos hasta N ⭐⭐⭐⭐☆

Compará verificar primos uno por uno vs Criba de Eratóstenes.

Método 1: Verificar cada número

// Para cada i de 2 a N:
//   Si es_primo(i): contar
// es_primo: O(√n) por cada número
// Total: O(N × √N)

Método 2: Criba

1
2
3
4
5
6
7
8
9
10
11
12
bool *criba(int n) {
    bool *es_primo = malloc((n+1) * sizeof(bool));
    // Inicializar todo en true
    for (int i = 2; i * i <= n; i++) {
        if (es_primo[i]) {
            for (int j = i * i; j <= n; j += i) {
                es_primo[j] = false;
            }
        }
    }
    return es_primo;
}

Orientación:


Ejercicio 24.21 - Subsecuencia Común Más Larga (LCS) ⭐⭐⭐⭐⭐

Analizá complejidad de LCS con programación dinámica.

Orientación:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int lcs(char *X, char *Y, int m, int n) {
    int dp[m+1][n+1];
    for (int i = 0; i <= m; i++) {
        for (int j = 0; j <= n; j++) {
            if (i == 0 || j == 0)
                dp[i][j] = 0;
            else if (X[i-1] == Y[j-1])
                dp[i][j] = dp[i-1][j-1] + 1;
            else
                dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
        }
    }
    return dp[m][n];
}

Ejercicio 24.22 - Multiplicación de Matrices ⭐⭐⭐⭐☆

Analizá complejidad de multiplicar dos matrices n×n.

Orientación:

1
2
3
4
5
6
7
8
9
10
void multiplicar(int A[N][N], int B[N][N], int C[N][N]) {
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            C[i][j] = 0;
            for (int k = 0; k < N; k++) {
                C[i][j] += A[i][k] * B[k][j];
            }
        }
    }
}

Ejercicio 24.23 - Torres de Hanoi ⭐⭐⭐⭐☆

Analizá complejidad de Torres de Hanoi.

Orientación:

1
2
3
4
5
6
7
8
9
void hanoi(int n, char origen, char destino, char auxiliar) {
    if (n == 1) {
        mover(origen, destino);
    } else {
        hanoi(n-1, origen, auxiliar, destino);
        mover(origen, destino);
        hanoi(n-1, auxiliar, destino, origen);
    }
}

Ejercicio 24.24 - Análisis Amortizado ⭐⭐⭐⭐⭐

Analizá costo amortizado de inserción en vector dinámico con duplicación.

Orientación:

1
2
3
4
5
6
void agregar(vector_t *v, int elem) {
    if (v->tamanio == v->capacidad) {
        redimensionar(v, v->capacidad * 2);  // O(n)
    }
    v->datos[v->tamanio++] = elem;  // O(1)
}

Ejercicio 24.25 - Comparar Estructuras de Datos ⭐⭐⭐⭐☆

Compará complejidad de operaciones en diferentes estructuras:

EstructuraBúsquedaInserciónEliminación
Array no ordenadoO(n)O(1) al finalO(n)
Array ordenadoO(log n)O(n)O(n)
Lista enlazadaO(n)O(1) al inicioO(1) con puntero
ABB balanceadoO(log n)O(log n)O(log n)
Hash tableO(1) promedioO(1) promedioO(1) promedio

Orientación:


Ejercicio 24.26 - Problema del Viajante (TSP) ⭐⭐⭐⭐⭐

Analizá complejidad de soluciones al TSP.

Fuerza Bruta:

// Probar todas las permutaciones de ciudades
// Cantidad de permutaciones: n!
// Complejidad: O(n!)

Programación Dinámica (Held-Karp):

// Estado: (ciudades visitadas, ciudad actual)
// Estados: 2ⁿ × n
// Complejidad: O(n² × 2ⁿ)

Orientación:


Ejercicio 24.27 - Optimización de Caché ⭐⭐⭐⭐⭐

Compará estos dos códigos para sumar matriz:

Versión 1:

for (i = 0; i < N; i++)
    for (j = 0; j < N; j++)
        suma += M[i][j];

Versión 2:

for (j = 0; j < N; j++)
    for (i = 0; i < N; i++)
        suma += M[i][j];

Orientación:


Ejercicio 24.28 - Medir Empíricamente ⭐⭐⭐⭐⭐

Implementá framework para medir tiempos y validar análisis teórico.

Orientación:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <time.h>

double medir_tiempo(void (*funcion)(int*, int), int *arr, int n) {
    clock_t inicio = clock();
    funcion(arr, n);
    clock_t fin = clock();
    return (double)(fin - inicio) / CLOCKS_PER_SEC;
}

// Probar con diferentes tamaños
for (int n = 1000; n <= 100000; n *= 2) {
    double tiempo = medir_tiempo(burbuja, arr, n);
    printf("n=%d, tiempo=%.4f\n", n, tiempo);
}

Notas Finales

Estas consignas desarrollan capacidad de analizar y comparar algoritmos teórica y empíricamente, esencial para diseñar soluciones eficientes.