Ciclos anidados en C++. Creando ciclos al interior de otros

Antes de comenzar, quisiera aclarar que los ciclos anidados NO son en sí una estructura de control, son de hecho un conjunto de estructuras de control anidadas, con anidadas me refiero a que una está dentro de la otra. De este modo un ciclo anidado (de hecho debería ser ciclos anidados, en plural :P) no es más que uno o más ciclos dentro de otro y de hecho no tenemos límite alguno para la cantidad de ciclos anidados.

Uno de los mayores problemas en cuanto a eficiencia que hay en la programación es tener ciclos anidados, son simplemente terribles para el rendimiento, sin embargo hay ocasiones en las que son indispensables. Como mencioné, no existe límite para la cantidad de ciclos anidados, sin embargo entre más ciclos tengamos, uno dentro de otro, más lenta será nuestra ejecución.

En conclusión los ciclos anidados no son una estructura de control por sí mismos, son un indicativo de que quizá deberíamos plantear la solución a algún problema si nos vemos obligados a usar ciclos anidados y más aún si es más de uno, sin embargo debemos saber que a veces son indispensables.

Hechas las aclaraciones previas en cuanto a rendimiento y definición vamos a ver unos ejemplos y el código básico de ciclos anidados en C++.

¿Cómo funciona un ciclo anidado?

Un único ciclo al interior de otro, funciona como un ciclo normal pero elevado al cuadrado, el ciclo externo comienza su ejecución con normalidad y luego va hasta el ciclo interno, y aquí es donde cambia todo; el ciclo externo no avanza hasta que el ciclo interno termine y una vez el ciclo externo avanza un paso vuelve a esperar al interno y así sucesivamente hasta que el externo termina, es por esto que es tan ineficiente el asunto.

Los ciclos anidados suelen usarse para llenar matrices (un vector de varias dimensiones) donde un ciclo recorre cada fila y otro cada columna o viceversa (depende de lo que necesitemos). De este modo entonces el ciclo externo empieza por la columna cero y el interno llena cada casilla de la columna cero y luego de la uno y las dos y así...

Notemos que entonces el ciclo externo (el de las columnas) no avanza a la siguiente hasta que el ciclo interno no llene todas las casillas de esa columna (lo cual tiene sentido, pues debe llenarse en orden).

Sintaxis de ciclos anidados:

La sintaxis es sencilla, un ciclo con otro adentro, y lo que nos haga falta, pues podemos poner varias sentencias adicionales al interior de cualquiera de los dos ciclos.

	
for(int i = valor inicial; i < valor final; i++)
{
	/*
		....
		....
		Bloque de Instrucciones....
		....
		....
	*/
	for(int j = valor inicial; j < valor final; j++)
	{
		/*
		....
		....
		Bloque interno de Instrucciones....
		....
		....
		*/
	}
	//Acá pueden haber más instrucciones
}
	

Como puedes ver entonces, es bastante simple, solo hay que notar algunas cosas interesantes: la primera y más importante es que la variable de control debe ser distinta en cada ciclo, fíjate que el ciclo externo usa la variable 'i' como variable de control mientras que el ciclo interno usa la 'j'. También debes notar que en el bloque interno de instrucciones podrías poner otro ciclo de cualquier tipo y al interior de este otro y así sucesivamente, cambiando el nombre de la variable de control (usar 'k' por ejemplo) para evitar mal funcionamiento. Finalmente debes saber que aunque son ciclos anidados no dejan de ser ciclos independientes en realidad, así que puedes poner las instrucciones que desees al interior de cualquier de ellos.

Nota: Cabe mencionar que no he hablado de tipos de ciclos, en realidad somos libres de anidar cualquier tipo de ciclo (for, while, do-while) y en cualquier cantidad, por ejemplo:

	
while(condición)
{
	/*
		Bloque de Instrucciones....
	*/

	for(int i = valor inicial; j < valor final; j++)
	{
		/*		
			Bloque interno de Instrucciones....
		*/
		while(condición2)
		{
			/*
				Más instrucciones
			*/
		}
	}
	//Acá pueden haber más instrucciones
}
	

Como puedes notar, básicamente no tienes restricciones en ello, de hecho al interior de cada ciclo puedes poner condicionales y demás estructuras que requieras.

Veamos entonces un ejemplo funcional para quedar claros.

Ejemplo de ciclos anidados en C++

Como quizá habrás adelantado en este primer ejemplo vamos a llenar una matriz de 10x10 (diez filas y diez columnas) con los número del 1 al 100 (1x1 hasta 10x10).

	
#include "iostream"
using namespace std;

int main()
{
	int matriz[10][10];

	for(int i = 0; i < 10; i++)//Ciclo externo
	{
		//Notemos que en ciclo interno no usamos la variable 'i' sino 'j'
		//Si usaramos i, el comportamiento sería inesperado
		for(int j = 0; j < 10; j++)//Ciclo interno
		{
			//Llenamos la matríz con los números del 1 al 100
			matriz[i][j] = (i+1)*(j+1);
			//(i+1)*(j+1) va desde 1x1 hasta 10x10 (aunque en desorden)
		}
	}

	system("pause");
	return 0;
}		
	

Segundo ejemplo de ciclos anidados en C++

Ahora vamos a hacer la función complementaria, vamos a recorrer la matriz usando ciclos anidados y a mostrar los valores en ésta.

	
#include "iostream"
using namespace std;

int main()
{
	//Suponiendo que tenemos una matríz llena llamada matrix
	for(int i = 0; i < 10; i++)//Ciclo externo
	{
		//Recuerda: En ciclo interno no usamos la variable 'i' sino 'j'
		for(int j = 0; j < 10; j++)//Ciclo interno
		{
			//Mostramos por pantalla el valor de la fila i columna j
			cout << matriz[i][j] << "\n";
		}
	}

	system("pause");
	return 0;
}		
	

Ten en cuenta que este ejemplo no funcionaría por sí solo, puesto que estamos recorriendo una matriz que ya está llena (como lo hicimos en el primer ejemplo). El código completo funcional, donde llenamos y luego mostramos la matriz, sería el siguiente:

Ejemplo completo y funcional

Vamos entonces a juntar ambos códigos para realizar ambas tareas (recorrer y mostrar la matriz) usando ciclos anidados.

	
#include "iostream"
using namespace std;

int main()
{
	int matriz[10][10];

	for(int i = 0; i < 10; i++)//Ciclo externo
	{
		//Notemos que en ciclo interno no usamos la variable 'i' sino 'j'
		//Si usaramos i, el comportamiento sería inesperado
		for(int j = 0; j < 10; j++)//Ciclo interno
		{
			//Llenamos la matríz con los números del 1 al 100
			matriz[i][j] = (i+1)*(j+1);
			//(i+1)*(j+1) va desde 1x1 hasta 10x10
		}
	}

	for(int i = 0; i < 10; i++)//Ciclo externo
	{
		for(int j = 0; j < 10; j++)//Ciclo interno
		{
			//Mostramos por pantalla el valor de la fila i columna j
			cout << matriz[i][j] << "\n";
		}
	}

	system("pause");
	return 0;
}	
	

Nota: Recuerda que si no es clara alguna de las líneas de estos códigos anteriores, te recomiendo visitar los contenidos anteriores o dejar un comentario al final de la sección con tu pregunta.

En efecto los ciclos anidados son muy interesantes y también útiles para múltiples situaciones, pero debes recordar que el tema de la eficiencia es un poco delicado, es recomendable evitarlos aunque no temerles, pues hay casos en los que son fundamentales e indispensables. Cuando vayas a usar un ciclo anidado detente un par de minutos y piensa si es realmente necesario usarlo o si puede haber una manera más efectiva de conseguir el mismo resultado; repito: habrá casos en los que sea indispensable usarlos, así que no les temas pues en algún momento será imprescindible usar un hermoso ciclo anidado, pues por alguna razón el lenguaje nos permite crearlos. Así que será nuestra experiencia y pericia la que nos dirá cuando es realmente necesario usarlos.

Ahora... es todo en esta sección :), podemos entonces continuar ahora con el siguiente contenido que son las estructuras de datos en C++, recuerda también dejar tus comentarios y/o preguntas en la sección de comentarios

La última actualización de este artículo fue hace 1 año