1. Bucles sencillos
Ejercicio 1
function ejercicio1(int n)
for (int i = 0; i < n; i += 3) // Línea 1
print(i) // Línea 2
end_for // Línea 3
return n // Línea 4
end_function
1.1 Cálculo del 
El tiempo de ejecución de la función viene dado por la suma del tiempo de ejecución del bucle y el tiempo de ejecución de la operación de retorno:
Donde:
-
es el tiempo de ejecución del bucle (líneas 1-3).
-
es el tiempo de ejecución de la línea 4.
Como , donde
es el tiempo constante de la operación de retorno:
Para calcular vamos a reescribir el bucle de la siguiente manera:
for (int i = 0; i <= n - 1; i += 3) // Línea 1
print(i) // Línea 2
end_for // Línea 3
Hemos reescrito la condición original como
para identificar el límite superior del intervalo, lo que simplifica la construcción del sumatorio.
Para determinar el número de iteraciones del bucle (líneas 1-3), analizamos la progresión de los valores que toma la variable :
-
Límite inferior:
-
Límite superior:
-
Incremento: 3 en cada paso (
)
Dado que el bucle no se incrementa de 1 en 1, calculamos el número total de iteraciones aplicando la fórmula de los términos de una progresión aritmética:
Sustituyendo los valores de nuestro bucle:
Podemos expresar el tiempo de ejecución del bucle como un sumatorio donde el índice recorre desde la primera hasta la última iteración:
Donde es el tiempo constante de las operaciones dentro del bucle. Resolviendo el sumatorio obtenemos:
Simplificando los términos de la expresión:
Sustituyendo en la expresión original:
1.2 Cálculo del orden de complejidad 
En el análisis asintótico, despreciamos las constantes multiplicativas y los términos de menor orden:
-
El término de mayor orden es
.
-
Las constantes
,
y
no afectan al crecimiento asintótico.
El algoritmo tiene una complejidad lineal, ya que el número de operaciones crece de manera directamente proporcional a .
Ejercicio 2
function ejercicio2(int n)
for (int i = 0; i < n/2; i += 5) // Línea 1
print(i) // Línea 2
end_for // Línea 3
return n // Línea 4
end_function
2.1 Cálculo del 
El tiempo de ejecución de la función viene dado por la suma del tiempo de ejecución del bucle y el tiempo de ejecución de la operación de retorno:
Donde:
-
es el tiempo de ejecución del bucle (líneas 1-3).
-
es el tiempo de ejecución de la línea 4.
Como , donde
es el tiempo constante de la operación de retorno:
Para calcular vamos a reescribir el bucle de la siguiente manera:
for (int i = 0; i <= (n/2) - 1; i += 5) // Línea 1
print(i) // Línea 2
end_for // Línea 3
Hemos reescrito la condición original como
para identificar el límite superior del intervalo, lo que simplifica la construcción del sumatorio.
Para determinar el número de iteraciones del bucle (líneas 1-3), analizamos la progresión de los valores que toma la variable :
-
Límite inferior:
-
Límite superior:
-
Incremento: 5 en cada paso (
)
Dado que el bucle no se incrementa de 1 en 1, calculamos el número total de iteraciones aplicando la fórmula de los términos de una progresión aritmética:
Sustituyendo los valores de nuestro bucle:
Podemos expresar el tiempo de ejecución del bucle como un sumatorio donde el índice recorre desde la primera hasta la última iteración:
Donde es el tiempo constante de las operaciones dentro del bucle. Resolviendo el sumatorio obtenemos:
Simplificando los términos de la expresión:
Sustituyendo en la expresión original:
2.2 Cálculo del orden de complejidad 
En el análisis asintótico, despreciamos las constantes multiplicativas y los términos de menor orden:
-
El término de mayor orden es
.
-
Las constantes
,
y
no afectan al crecimiento asintótico.
El algoritmo tiene una complejidad lineal, ya que el número de operaciones crece de manera directamente proporcional a .
Ejercicio 3
function ejercicio3(int n)
for (int i = n; i > 0; i--) // Línea 1
print(i) // Línea 2
end_for // Línea 3
return n // Línea 4
end_function
3.1 Cálculo del 
El tiempo de ejecución de la función viene dado por la suma del tiempo de ejecución del bucle y el tiempo de ejecución de la operación de retorno:
Donde:
-
es el tiempo de ejecución del bucle (líneas 1-3).
-
es el tiempo de ejecución de la línea 4.
Como , donde
es el tiempo constante de la operación de retorno:
Para determinar el número de iteraciones del bucle (líneas 1-3), analizamos la progresión de los valores que toma la variable :
-
Valor inicial:
-
Condición:
-
Decremento: 1 en cada paso (
)
La lógica en bucles con decremento es idéntica a la de los bucles con incremento. La siguiente fórmula nos permite calcular el número de iteraciones basándonos en los límites del intervalo:
Sustituyendo los valores de nuestro bucle:
Podemos expresar el tiempo de ejecución del bucle como un sumatorio donde el índice recorre desde la primera hasta la última iteración:
Donde es el tiempo constante de las operaciones dentro del bucle. Resolviendo el sumatorio obtenemos:
Sustituyendo en la expresión original:
3.2 Cálculo del orden de complejidad 
Para determinar el orden de complejidad, realizamos el análisis asintótico de la expresión :
-
Descartamos los términos de menor orden. La constante
es un término de orden inferior comparado con
.
-
Descartamos las constantes multiplicativas. La constante
no afecta al crecimiento asintótico de la función.
El término dominante es , por lo que el algoritmo tiene una complejidad lineal.
Ejercicio 4
function ejercicio4(int n)
for (int i = 1; i <= n; i = i * 2) // Línea 1
print(i) // Línea 2
end_for // Línea 3
return n // Línea 4
end_function
4.1 Cálculo del 
El tiempo de ejecución de la función viene dado por la suma del tiempo de ejecución del bucle y el tiempo de ejecución de la operación de retorno:
Donde:
-
es el tiempo de ejecución del bucle (líneas 1-3).
-
es el tiempo de ejecución de la línea 4.
Como , donde
es el tiempo constante de la operación de retorno:
Para determinar el número de iteraciones del bucle (líneas 1-3), analizamos la progresión geométrica de los valores que toma la variable :
-
Iteración 0:
-
Iteración 1:
-
Iteración 2:
-
…
-
Iteración k:
El bucle continúa mientras se cumpla la condición . Para despejar el número de iteraciones en la última vuelta (
), resolvemos la siguiente inecuación:
|
Por las propiedades de los logaritmos |
El número total de iteraciones es , contando desde la primera iteración
hasta la última
.
Podemos expresar el tiempo de ejecución del bucle como un sumatorio donde el índice representa cada iteración:
Donde es el tiempo constante de las operaciones dentro del bucle. Resolviendo el sumatorio obtenemos:
Sustituyendo en la expresión original:
4.2 Cálculo del orden de complejidad 
Para determinar el orden de complejidad, realizamos el análisis asintótico:
-
Descartamos los términos de menor orden. Las constantes
y
son términos de orden inferior comparados con
.
-
Descartamos las constantes multiplicativas. Las constantes no afectan al crecimiento asintótico.
-
Cambio de base del logaritmo. Todas las funciones logarítmicas pertenecen al mismo orden de complejidad, independientemente de la base.
El término dominante es , por lo que el algoritmo tiene una complejidad logarítmica.
Ejercicio 5
function ejercicio5(int n)
for (int i = n; i >= 1; i = i / 2) // Línea 1
print(i) // Línea 2
end_for // Línea 3
return n // Línea 4
end_function
5.1 Cálculo del 
El tiempo de ejecución de la función viene dado por la suma del tiempo de ejecución del bucle y el tiempo de ejecución de la operación de retorno:
Donde:
-
es el tiempo de ejecución del bucle (líneas 1-3).
-
es el tiempo de ejecución de la línea 4.
Como , donde
es el tiempo constante de la operación de retorno:
Para determinar el número de iteraciones del bucle (líneas 1-3), analizamos la progresión geométrica decreciente de los valores que toma la variable :
-
Iteración 0:
-
Iteración 1:
-
Iteración 2:
-
…
-
Iteración k:
El bucle continúa mientras se cumpla la condición . Para despejar el número de iteraciones en la última vuelta (
), resolvemos la siguiente inecuación:
|
Por las propiedades de los logaritmos |
El número total de iteraciones es , contando desde la primera iteración
hasta la última
.
Podemos expresar el tiempo de ejecución del bucle como un sumatorio donde el índice representa cada iteración:
Donde es el tiempo constante de las operaciones dentro del bucle. Resolviendo el sumatorio obtenemos:
Sustituyendo en la expresión original:
5.2 Cálculo del orden de complejidad 
Para determinar el orden de complejidad, realizamos el análisis asintótico:
-
Descartamos los términos de menor orden. Las constantes
y
son términos de orden inferior comparados con
.
-
Descartamos las constantes multiplicativas. Las constantes no afectan al crecimiento asintótico.
-
Cambio de base del logaritmo. Todas las funciones logarítmicas pertenecen al mismo orden de complejidad, independientemente de la base.
El término dominante es , por lo que el algoritmo tiene una complejidad logarítmica.
Ejercicio 6
function ejercicio6(int n)
for (int i = 1; i <= n; i = i * 3) // Línea 1
print(i) // Línea 2
end_for // Línea 3
return n // Línea 4
end_function
6.1 Cálculo del 
El tiempo de ejecución de la función viene dado por la suma del tiempo de ejecución del bucle y el tiempo de ejecución de la operación de retorno:
Donde:
-
es el tiempo de ejecución del bucle (líneas 1-3).
-
es el tiempo de ejecución de la línea 4.
Como , donde
es el tiempo constante de la operación de retorno:
Para determinar el número de iteraciones del bucle (líneas 1-3), analizamos la progresión geométrica de los valores que toma la variable :
-
Iteración 0:
-
Iteración 1:
-
Iteración 2:
-
…
-
Iteración k:
El bucle continúa mientras se cumpla la condición . Para despejar el número de iteraciones en la última vuelta (
), resolvemos la siguiente inecuación:
|
Por las propiedades de los logaritmos |
El número total de iteraciones es , contando desde la primera iteración
hasta la última
.
Podemos expresar el tiempo de ejecución del bucle como un sumatorio donde el índice representa cada iteración:
Donde es el tiempo constante de las operaciones dentro del bucle. Resolviendo el sumatorio obtenemos:
Sustituyendo en la expresión original:
6.2 Cálculo del orden de complejidad 
Para determinar el orden de complejidad, realizamos el análisis asintótico:
-
Descartamos los términos de menor orden. Las constantes
y
son términos de orden inferior comparados con
.
-
Descartamos las constantes multiplicativas. Las constantes no afectan al crecimiento asintótico.
-
Cambio de base del logaritmo. Todas las funciones logarítmicas pertenecen al mismo orden de complejidad, independientemente de la base (recordemos que
, siendo
una constante).
El término dominante es , por lo que el algoritmo tiene una complejidad logarítmica.
2. Bucles anidados independientes
Ejercicio 7
function ejercicio7(int n)
for (int i = 0; i < n/2; i++) // Línea 1
for(int j = 0; j < n/2; j++) // Línea 2
print(i + j) // Línea 3
end_for // Línea 4
end_for // Línea 5
return n // Línea 6
end_function
7.1 Cálculo del 
El tiempo de ejecución de la función viene dado por la suma del tiempo de ejecución del bucle anidado y el tiempo de ejecución de la operación de retorno:
Como , la expresión es:
Para calcular , analizamos la estructura anidada. El tiempo total es la suma de las ejecuciones del bucle interno multiplicada por las iteraciones del bucle externo.
Para determinar el número de iteraciones de ambos bucles:
-
Bucle externo (i): Va de
a
. El número de iteraciones es
.
-
Bucle interno (j): Va de
a
. El número de iteraciones es
.
Podemos expresar el tiempo de ejecución total como un sumatorio anidado:
Donde es el tiempo constante de la operación dentro del bucle interno. Resolviendo el sumatorio interno:
Sustituyendo en el sumatorio externo:
Sustituyendo en la expresión original:
7.2 Cálculo del orden de complejidad 
Para determinar el orden de complejidad, realizamos el análisis asintótico:
-
Descartamos los términos de menor orden. La constante
es de orden inferior frente a
.
-
Descartamos las constantes multiplicativas. El factor
no afecta al crecimiento asintótico.
El término dominante es , por lo que el algoritmo tiene una complejidad cuadrática.
Ejercicio 8
function ejercicio8(int n)
int m = 3000 // Línea 1
for (int i = 0; i < n/2; i++) // Línea 2
for(int j = 0; j < m * 1000; j++) // Línea 3
print(i + j + m) // Línea 4
end_for // Línea 5
end_for // Línea 6
return n // Línea 7
end_function
8.1 Cálculo del 
El tiempo de ejecución de la función viene dado por la suma del tiempo de ejecución de la inicialización, el bucle anidado y el retorno:
Donde y
. La expresión se simplifica a:
Para calcular , analizamos las iteraciones de cada bucle:
-
Bucle externo (i): Va de
a
. El número de iteraciones es
.
-
Bucle interno (j): Va de
a
. Como
, el número de iteraciones es
.
Es muy importante observar que el número de iteraciones del bucle interno no depende de . Por tanto, el tiempo de ejecución del bucle interno es una constante
.
Podemos expresar el tiempo de ejecución del bucle total como:
Sustituyendo los valores constantes:
La expresión final de es:
8.2 Cálculo del orden de complejidad 
Para determinar el orden de complejidad, realizamos el análisis asintótico:
-
Descartamos los términos de menor orden. La constante
es despreciable frente al término que contiene
.
-
Descartamos las constantes multiplicativas. Aunque el factor multiplicativo
sea muy grande, sigue siendo una constante que no escala con el tamaño de la entrada
.
El término dominante es , por lo que el algoritmo tiene una complejidad lineal.
Ejercicio 9
function ejercicio9(int n)
int m = n / 10000 // Línea 1
for (int i = 0; i < n/2; i++) // Línea 2
for(int j = 0; j < m; j += 20) // Línea 3
print(i + j) // Línea 4
end_for // Línea 5
end_for // Línea 6
return n // Línea 7
end_function
9.1 Cálculo del 
El tiempo de ejecución de la función viene dado por la suma del tiempo de ejecución de la inicialización, el bucle anidado y el retorno:
Donde y
.
Para calcular , analizamos las iteraciones de cada bucle:
-
Bucle externo (i): Va de
a
. El número de iteraciones es
.
-
Bucle interno (j): Va de
a
con incrementos de 20. Dado que
, el número de iteraciones es
.
Podemos expresar el tiempo de ejecución del bucle total como un sumatorio anidado:
Resolviendo el sumatorio interno:
Sustituyendo en el sumatorio externo:
Sustituyendo en la expresión original de :
9.2 Cálculo del orden de complejidad 
Para determinar el orden de complejidad, realizamos el análisis asintótico:
-
Descartamos los términos de menor orden. Los términos
y las constantes son despreciables frente al crecimiento de
.
-
Descartamos las constantes multiplicativas. El factor
no afecta al crecimiento asintótico.
El término dominante es , por lo que el algoritmo tiene una complejidad cuadrática.
Ejercicio 10
function ejercicio10(int n)
int m = n * n // Línea 1
for (int i = n/2; i > 1; i = i / 3) // Línea 2
for(int j = 0; j < m; j++) // Línea 3
print(i + j) // Línea 4
end_for // Línea 5
end_for // Línea 6
return n // Línea 7
end_function
10.1 Cálculo del 
El tiempo de ejecución de la función viene dado por la suma del tiempo de ejecución de la inicialización, el bucle anidado y el retorno:
Donde y
. La expresión se simplifica a:
Para calcular , analizamos las iteraciones de cada bucle:
-
Bucle externo (i): Analizamos la progresión geométrica decreciente de los valores que toma la variable
, con valor inicial
y dividiéndose por 3 en cada paso (
). El bucle continúa mientras
. Despejando el número de iteraciones en la última vuelta (
):
El número de iteraciones es
.
|
Por las propiedades de los logaritmos |
-
Bucle interno (j): Va de
a
con incrementos de 1. Como
, el número de iteraciones es
.
Podemos expresar el tiempo de ejecución del bucle total como un sumatorio anidado:
Resolviendo el sumatorio interno:
Sustituyendo en el sumatorio externo:
Sustituyendo en la expresión original de :
10.2 Cálculo del orden de complejidad 
Para determinar el orden de complejidad, realizamos el análisis asintótico:
-
Descartamos los términos de menor orden. Las constantes
y
son despreciables frente al término dominante que incluye
y el logaritmo. Además, la constante aditiva
del logaritmo es de menor orden.
-
Descartamos las constantes multiplicativas. El factor
no afecta al crecimiento asintótico.
-
Cambio de base y constantes en el logaritmo. Recordamos que
. La resta de una constante no altera el orden asintótico, y la base del logaritmo se omite en la notación de orden de complejidad.
El término dominante es , por lo que el algoritmo tiene una complejidad cuadrática logarítmica.
Ejercicio 11
function ejercicio11(int n)
int m = 2147483647; //MAX_INTEGER // Línea 1
for (int i = 0; i < m; i++) // Línea 2
for(int j = m; j < m; j = j / 2) // Línea 3
print(i + j) // Línea 4
end_for // Línea 5
end_for // Línea 6
return n // Línea 7
end_function
11.1 Cálculo del 
El tiempo de ejecución de la función viene dado por la suma del tiempo de ejecución de la inicialización, el bucle anidado y el retorno:
Donde y
. La expresión se simplifica a:
Para calcular , analizamos las iteraciones de cada bucle:
-
Bucle interno (j): Su inicialización es
j = my su condición de continuación esj < m. Como la variablejcomienza con un valor igual am, la condiciónj < mes falsa desde la primera evaluación. Por lo tanto, el cuerpo del bucle interno (línea 4) no se ejecuta nunca (0 iteraciones). Sin embargo, evaluar la condición del bucle interno en cada iteración del bucle externo tiene un coste constante.
-
Bucle externo (i): Va de
a
con incrementos de 1. El número de iteraciones es exactamente
. Como
, este es un valor enorme, pero totalmente constante (no depende de la variable de entrada
).
El bucle externo se ejecuta veces, y en cada iteración solo se realiza la evaluación de la condición del bucle interno (
).
Podemos expresar el tiempo de ejecución del bucle total como un sumatorio:
Sustituyendo el valor constante de :
Sustituyendo en la expresión original de :
11.2 Cálculo del orden de complejidad 
Para determinar el orden de complejidad, realizamos el análisis asintótico:
-
El número de operaciones que realiza la función no depende del valor de
.
-
Todos los términos de la expresión
son valores constantes. En el análisis asintótico, toda expresión constante se agrupa y asimila a
.
Dado que el algoritmo requiere el mismo tiempo de ejecución independientemente del tamaño de la entrada, tiene una complejidad constante.
3. Bucles anidados dependientes
Ejercicio 12
function ejercicio12(int n)
for (int i = 1; i <= n; i++) // Línea 1
for(int j = 1; j <= i; j++) // Línea 2
print(i + j) // Línea 3
end_for // Línea 4
end_for // Línea 5
return n // Línea 6
end_function
12.1 Cálculo del 
El tiempo de ejecución de la función viene dado por la suma del tiempo de ejecución del bucle anidado y el retorno:
Como , la expresión se simplifica a:
Para calcular , analizamos las iteraciones de cada bucle. A diferencia de los bucles anidados independientes, en este caso el límite superior del bucle interno depende de la variable del bucle externo.
-
Bucle externo (i): Va de
a
con incrementos de 1.
-
Bucle interno (j): Va de
a
con incrementos de 1. El número de iteraciones para un valor dado de
es exactamente
.
Podemos expresar el tiempo de ejecución del bucle total mediante un doble sumatorio:
Donde es el coste constante de las operaciones ejecutadas en el bucle interno (línea 3).
Resolvemos primero el sumatorio interno:
Ahora sustituimos este resultado en el sumatorio externo:
|
Recordamos que la suma de los |
Sustituyendo la fórmula anterior en la expresión del sumatorio:
Sustituyendo en la expresión original de :
12.2 Cálculo del orden de complejidad 
Para determinar el orden de complejidad, realizamos el análisis asintótico:
-
Descartamos los términos de menor orden. Los términos proporcionales a
y las constantes (
) son despreciables frente al término cuadrático
cuando
es grande.
-
Descartamos las constantes multiplicativas. El factor
no afecta al crecimiento asintótico de la función.
El término dominante es , por lo que el algoritmo tiene una complejidad cuadrática.
Ejercicio 13
function ejercicio13(int n)
for (int i = 1; i <= n * n - 10; i++) // Línea 1
for(int j = 1; j <= i; j++) // Línea 2
print(i + j) // Línea 3
end_for // Línea 4
end_for // Línea 5
return n // Línea 6
end_function
13.1 Cálculo del 
El tiempo de ejecución de la función viene dado por la suma del tiempo de ejecución del bucle anidado y el retorno:
Como , la expresión se simplifica a:
Para calcular , analizamos las iteraciones de cada bucle. A diferencia de los bucles anidados independientes, en este caso el límite superior del bucle interno depende de la variable del bucle externo.
-
Bucle externo (i): Va de
a
con incrementos de 1.
-
Bucle interno (j): Va de
a
con incrementos de 1. El número de iteraciones para un valor dado de
es exactamente
.
Podemos expresar el tiempo de ejecución del bucle total mediante un doble sumatorio:
Donde es el coste constante de las operaciones ejecutadas en el bucle interno (línea 3).
Resolvemos primero el sumatorio interno:
Ahora sustituimos este resultado en el sumatorio externo:
|
Recordamos que la suma de los |
Aplicando la fórmula para el límite :
Desarrollando el producto polinómico:
Sustituyendo en la expresión original de :
13.2 Cálculo del orden de complejidad 
Para determinar el orden de complejidad, realizamos el análisis asintótico:
-
Descartamos los términos de menor orden. Los términos proporcionales a
y las constantes (
) son despreciables frente al término polinómico de mayor grado
cuando
es grande.
-
Descartamos las constantes multiplicativas. El factor
no afecta al crecimiento asintótico de la función.
El término dominante es , por lo que el algoritmo tiene una complejidad polinómica de grado 4.
Ejercicio 14
function ejercicio14(int n)
for (int i = 1; i <= n; i++) // Línea 1
for(int j = 1; j <= i; j++) // Línea 2
for(int k = 1; k <= i; k++) // Línea 3
print(i + j + k) // Línea 4
end_for // Línea 5
end_for // Línea 6
end_for // Línea 7
return n // Línea 8
end_function
14.1 Cálculo del 
El tiempo de ejecución de la función viene dado por la suma del tiempo de ejecución del bucle anidado y el retorno:
Como , la expresión se simplifica a:
Para calcular , analizamos las iteraciones de cada bucle. A diferencia de los bucles anidados independientes, en este caso los límites superiores de los bucles interno e intermedio dependen de la variable del bucle externo.
-
Bucle externo (i): Va de
a
con incrementos de 1.
-
Bucle intermedio (j): Va de
a
con incrementos de 1. Su número de iteraciones es
.
-
Bucle interno (k): Va de
a
con incrementos de 1. Su número de iteraciones es
.
Dado que los bucles j y k son independientes entre sí pero ambos dependen de i, el número total de iteraciones de los dos bucles más internos para un valor dado de es
.
Podemos expresar el tiempo de ejecución del bucle total mediante un triple sumatorio:
Donde es el coste constante de las operaciones ejecutadas en el bucle interno (línea 4).
Resolvemos los sumatorios de adentro hacia afuera. Primero el sumatorio interno en :
Luego el sumatorio intermedio en :
Ahora sustituimos este resultado en el sumatorio externo en :
|
Recordamos que la suma de los cuadrados de los |
Aplicando esta fórmula:
Desarrollando la fracción:
Sustituyendo en la expresión original de :
14.2 Cálculo del orden de complejidad 
Para determinar el orden de complejidad, realizamos el análisis asintótico:
-
Descartamos los términos de menor orden. Los términos proporcionales a
,
y las constantes (
) son despreciables frente al término polinómico de mayor grado
cuando
es grande.
-
Descartamos las constantes multiplicativas. El factor
no afecta al crecimiento asintótico de la función.
El término dominante es , por lo que el algoritmo tiene una complejidad cúbica (polinómica de grado 3).
Ejercicio 15
function ejercicio15(int n)
for (int i = 1; i <= n; i++) // Línea 1
for(int j = 1; j <= i; j++) // Línea 2
for(int k = 1; k <= j; k++) // Línea 3
print(i + j + k) // Línea 4
end_for // Línea 5
end_for // Línea 6
end_for // Línea 7
return n // Línea 8
end_function
15.1 Cálculo del 
El tiempo de ejecución de la función viene dado por la suma del tiempo de ejecución del bucle anidado y el retorno:
Como , la expresión se simplifica a:
Para calcular , analizamos las iteraciones de cada bucle. A diferencia de los bucles anidados independientes, en este caso los límites superiores de los bucles interno e intermedio dependen de la variable del bucle externo.
-
Bucle externo (i): Va de
a
con incrementos de 1.
-
Bucle intermedio (j): Va de
a
con incrementos de 1.
-
Bucle interno (k): Va de
a
con incrementos de 1. Su número de iteraciones depende del valor de
.
Dado que los bucles están anidados y cada uno depende del anterior, el número total de iteraciones se calcula mediante un triple sumatorio:
Donde es el coste constante de las operaciones ejecutadas en el bucle interno (línea 4).
Resolvemos los sumatorios de adentro hacia afuera. Primero el sumatorio interno en :
Luego el sumatorio intermedio en :
Ahora sustituimos este resultado en el sumatorio externo en :
|
Recordamos las fórmulas de las sumas: |
Aplicando las fórmulas:
Para simplificar esta expresión, realizamos los siguientes pasos algebraicos.
Factorizamos el término común :
Sumamos las fracciones dentro del paréntesis (denominador común 6):
Multiplicamos los resultados para obtener la fórmula compacta:
Desarrollamos el polinomio y distribuimos el denominador:
Sustituyendo en la expresión original de :
15.2 Cálculo del orden de complejidad 
Para determinar el orden de complejidad, realizamos el análisis asintótico:
-
Descartamos los términos de menor orden. Los términos proporcionales a
,
y las constantes (
) son despreciables frente al término polinómico de mayor grado
cuando
es grande.
-
Descartamos las constantes multiplicativas. El factor
no afecta al crecimiento asintótico de la función.
El término dominante es , por lo que el algoritmo tiene una complejidad cúbica (polinómica de grado 3).
4. Bucles con while
Ejercicio 16
function ejercicio16(int n)
while (n > 1) // Línea 1
print(n) // Línea 2
n = n / 2 // Línea 3
end_while // Línea 4
return 0 // Línea 5
end_function
16.1 Cálculo del 
El tiempo de ejecución de la función viene dado por la suma del tiempo de ejecución del bucle y el tiempo de ejecución de la operación de retorno:
Como , donde
es el tiempo constante de la operación de retorno:
Para determinar el número de iteraciones del bucle while (líneas 1-4), analizamos la progresión geométrica decreciente de los valores que toma la variable :
-
Iteración 0:
-
Iteración 1:
-
Iteración 2:
-
…
-
Iteración k:
El bucle continúa iterando mientras se cumpla la condición . Para despejar el número de iteraciones en la última vuelta (
), establecemos la inecuación para el límite de iteraciones:
|
Por las propiedades de los logaritmos |
El número total de iteraciones está acotado por .
Podemos expresar el tiempo de ejecución del bucle como un sumatorio donde el índice representa cada iteración:
Donde es el tiempo constante de las operaciones dentro del bucle (líneas 2 y 3). Resolviendo el sumatorio obtenemos:
Sustituyendo en la expresión original:
16.2 Cálculo del orden de complejidad 
Para determinar el orden de complejidad, realizamos el análisis asintótico:
-
Descartamos los términos de menor orden. La constante
es un término de orden inferior comparado con
.
-
Descartamos las constantes multiplicativas. La constante
no afecta al crecimiento asintótico.
-
Cambio de base del logaritmo. Todas las funciones logarítmicas pertenecen al mismo orden de complejidad, independientemente de la base.
El término dominante es , por lo que el algoritmo tiene una complejidad logarítmica.
5. Algoritmos recursivos
Ejercicio 17
long int factorial(long int n) {
if (n <= 1) // Línea 1
return 1; // Línea 2
else // Línea 3
return n * factorial(n - 1); // Línea 4
}
17.1 Cálculo de la ecuación de recurrencia
El tiempo de ejecución de un algoritmo recursivo se expresa mediante una ecuación de recurrencia, donde se separa el tiempo de ejecución del caso base del tiempo del caso recursivo.
Para la función factorial(n), consideramos:
-
: Tiempo de ejecución del caso base (
).
-
: Tiempo constante de las operaciones realizadas en cada llamada recursiva (comparaciones, resta, multiplicación y retorno).
La ecuación de recurrencia queda expresada como:
17.2 Resolución de la ecuación 
Para encontrar una expresión no recursiva de , utilizamos el método de sustitución:
-
Partimos de la expresión original para el caso recursivo:
-
Obtenemos la expresión de
sustituyendo
por
en la ecuación original:
-
Sustituimos la ecuación (2) en la (1):
-
Repetimos el proceso para
:
-
Podemos inferir que tras
sustituciones, el tiempo de ejecución está dado por:
-
El proceso de sustitución termina cuando alcanzamos el caso base (
). Despejando
:
-
Sustituimos el valor de
en la ecuación (6):
-
Como sabemos que
(caso base), la expresión final es:
17.3 Cálculo del orden de complejidad 
Para determinar el orden de complejidad, realizamos el análisis asintótico sobre la expresión obtenida:
-
Descartamos los términos de menor orden. En la expresión
, el término dominante es el que depende de
. La constante
es despreciable cuando
es grande.
-
Descartamos las constantes multiplicativas. El factor
no afecta a la tasa de crecimiento de la función.
El término dominante es , por lo que el algoritmo tiene una complejidad lineal.
Ejercicio 18
int recursiva1(int n) {
if (n <= 1) // Línea 1
return 1; // Línea 2
else // Línea 3
return 2 * recursiva1(n / 2); // Línea 4
}
18.1 Cálculo de la ecuación de recurrencia
Para la función recursiva1(n), definimos:
-
: Tiempo de ejecución del caso base (
).
-
: Tiempo constante de las operaciones realizadas en cada llamada recursiva (comparación, división por 2, multiplicación por 2 y retorno).
La ecuación de recurrencia queda expresada como:
18.2 Resolución de la ecuación 
Para encontrar una expresión no recursiva de , utilizamos el método de sustitución:
-
Partimos de la expresión original para el caso recursivo:
-
Obtenemos la expresión de
sustituyendo
por
en la ecuación original:
-
Sustituimos la ecuación (2) en la (1):
-
Repetimos el proceso para el siguiente paso:
-
Podemos inferir que tras
sustituciones, el tiempo de ejecución está dado por:
-
El proceso de sustitución termina cuando alcanzamos el caso base (
). Despejamos
:
-
Sustituimos el valor de
en la ecuación (6):
-
Como sabemos que
(caso base), la expresión final es:
18.3 Cálculo del orden de complejidad 
Para determinar el orden de complejidad, realizamos el análisis asintótico sobre la expresión obtenida:
-
Descartamos los términos de menor orden. La constante
es un término de orden inferior comparado con
.
-
Descartamos las constantes multiplicativas. El factor
no afecta a la tasa de crecimiento asintótico.
-
Cambio de base del logaritmo. Todas las funciones logarítmicas pertenecen al mismo orden de complejidad, independientemente de la base del logaritmo.
El término dominante es , por lo que el algoritmo tiene una complejidad logarítmica.
Ejercicio 19
int recursiva2(int n, int x) {
int i;
if (n <= 1) // Línea 1
return 1; // Línea 2
else { // Línea 3
for (i = 1; i <= n; i++) // Línea 4
x = x + 1; // Línea 5
return recursiva2(n - 1, x); // Línea 6
}
}
19.1 Cálculo de la ecuación de recurrencia
Para la función recursiva2(n, x), definimos:
-
: Tiempo de ejecución del caso base (
).
-
: Tiempo constante asociado a cada iteración del bucle
for(líneas 4 y 5). -
Consideramos que el resto de operaciones constantes se asimilan en el coste del bucle o en las constantes finales.
La ecuación de recurrencia es:
19.2 Resolución de la ecuación 
Para encontrar una expresión no recursiva de , utilizamos el método de sustitución:
-
Partimos de la expresión original para el caso recursivo:
-
Obtenemos la expresión de
sustituyendo en la ecuación original:
-
Sustituimos la ecuación (2) en la (1):
-
Repetimos el proceso para
:
-
Podemos inferir que tras
sustituciones, el tiempo de ejecución está dado por:
-
El proceso termina cuando alcanzamos el caso base (
), lo que implica
. Sustituimos en la ecuación (6):
-
Evaluamos el sumatorio. Representa la suma de los enteros desde
hasta
:
-
Aplicando la fórmula de la suma de los
primeros enteros (
):
19.3 Cálculo del orden de complejidad 
Para determinar el orden de complejidad, realizamos el análisis asintótico sobre la expresión obtenida:
-
Descartamos los términos de menor orden. Los términos proporcionales a
y las constantes son despreciables frente a
cuando
es grande.
-
Descartamos las constantes multiplicativas. El factor
no afecta al crecimiento asintótico.
El término dominante es , por lo que el algoritmo tiene una complejidad cuadrática.
Ejercicio 20
int recursiva3(int n) {
if (n <= 1) // Línea 1
return 1; // Línea 2
else // Línea 3
return recursiva3(n - 1) + recursiva3(n - 1); // Línea 4
}
20.1 Cálculo de la ecuación de recurrencia
Para la función recursiva3(n), definimos:
-
: Tiempo de ejecución del caso base (
).
-
: Tiempo constante asociado a las operaciones en el caso recursivo (comparación, resta, suma de los resultados y retorno).
La ecuación de recurrencia es:
20.2 Resolución de la ecuación 
Para encontrar una expresión no recursiva de , utilizamos el método de sustitución:
-
Partimos de la expresión original para el caso recursivo:
-
Obtenemos la expresión de
sustituyendo en la ecuación original:
-
Sustituimos la ecuación (2) en la (1):
-
Repetimos el proceso para
:
-
Podemos inferir que tras
sustituciones, el tiempo de ejecución está dado por:
-
El proceso termina cuando alcanzamos el caso base (
), lo que implica
. Sustituimos en la ecuación (6):
-
Como sabemos que
, simplificamos la expresión:
20.3 Cálculo del orden de complejidad 
Para determinar el orden de complejidad, realizamos el análisis asintótico sobre la expresión obtenida:
-
Descartamos los términos de menor orden. La constante
es despreciable frente al crecimiento exponencial de
cuando
es grande.
-
Descartamos las constantes multiplicativas. El factor
no afecta a la tasa de crecimiento asintótico.
El término dominante es , por lo que el algoritmo tiene una complejidad exponencial.
6. Referencias
-
Algorithm analysis: Exercises with solutions for AAHPS tutorials. Matej Pičulin.
-
Analysis of Algorithms: Practice Examples. Princeton University. Ibrahim Albluw.
-
Introducción al Análisis y al Diseño de Algoritmos. María del Carmen Gómez Fuentes, Jorge Cervantes Ojeda.
7. Licencia
Licencia CC BY-NC-ND 4.0
Este material ha sido creado por José Juan Sánchez Hernández © 2026, y su contenido se distribuye bajo una licencia Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International.
Esta licencia exige que quienes reutilicen el material otorguen el debido crédito al autor. Permite copiar y redistribuir el material en cualquier medio o formato, únicamente en su forma original, y solo para fines no comerciales.