8. 중첩 반복문

Isaiah IM·2023년 2월 1일
0

java basic

목록 보기
9/38
post-thumbnail

1. 중첩 반복문

중첩 반복문이란 반복문이 중첩된 경우를 의미한다.

중첩 반복문은 반복문이 중첩된 형태로 다음과 같이 나타낸다.

while(condition1){
...// code

	while(condition2){// 중첩 반복문
    	...// code
    }
    
}

이때, while 반복문을 포함한 모든 반복문 역시 중첩 반복문으로 사용이 가능하다.

보다 원활한 이해를 위해 직접 코드를 작성하면서 용도를 알아보도록 하자.
구구단을 출력하는 프로그램을 개발한다 가정하자.

만약 중첩 반복문을 사용하지 않을 경우 이런식으로 프로그램을 개발해야 한다.

for(int i=1; i=9; i++){// 1단
	System.out.println("1*"+ i+"=" +i);
}

for(int i=1; i=9; i++){// 2단
	System.out.println("2*"+ i+"=" + 2*i);
}

for(int i=1; i=9; i++){// 3단
	System.out.println("1*"+ i+"=" + 3*i);
}
....

반면에 중첩 반복문을 사용하면 보다 간단하게 나타낼 수 있다.

본격적인 설계에 앞서 효율적으로 중첩 반복문을 사용하기 위해서는 반복되는 규칙을 찾아야 한다.

먼저 구구단의 경우 1*9 부터 9*9까지 각각 곱하게 된다.
즉, 다음과 같이 표현이 된다.
1*1, 1*2, 1*3, ..... ,1*9
2*1, 2*2, 2*3, ..... ,2*9
3*1, 3*2, 3*3, ..... ,3*9
...
9*1, 9*2, 9*3, ..... ,9*9

즉, 두 숫자 모두 1부터 시작해 두번째 숫자가 9까지 차례대로 1씩 증가하고, 두번째 숫자가 9가 되면 첫번째 숫자가 1이 증가하고 다시 두번째 숫자가 9까지 차례대로 증가한다.
이러한 규칙을 반복문을 이용해 구현하면 다음과 같다.

먼저, 첫번째 숫자가 1부터 9까지 증가하는 코드를 작성하면 다음과 같다.

for(int firstNum=1; firstNum<=9; firstNum++){
...// code
}

다음으로, 두번째 숫자가 1에서 9까지 증가한 이후에 첫번째 숫자가 증가하게 되므로, 두번째 숫자가 증가하는 코드를 첫번째 반복문 안에 작성하면 다음과 같다.

for(int firstNum=1; firstNum<=9; firstNum++){// 반복문이 한번 실행 후 첫번째 숫자가 증가.
	for(int secondNum=1; secondNum<=9; secondNum++){// 두번째 숫자가 9까지 증가한 이후 이 반복문을 벗어난다.
    	System.out.println(firstNum + " * " + secondNum+ " = " + firstNum*secondNum);
	}
}

코드를 직접 동작시켜 보면 정상적으로 동작함을 확인할 수 있다.

이와 같이 중첩 반복문은 구구단과 같이 특정한 규칙이 반복될 때 매우 유용하게 사용할 수 있다.

다음으로 만약 다음과 같은 별을 찍는 프로그램을 설계해 보도록 하자.

*
**
***
****
*****

규칙을 살펴보면 다음과 같다.

첫번째 줄은 별이 1개 찍힌다.
두번째 줄은 별이 2개 찍힌다.
두번째 줄은 별이 3개 찍힌다.
두번째 줄은 별이 4개 찍힌다.
두번째 줄은 별이 5개 찍힌다.

즉, n번째 줄에서는 n개의 별이 찍히게 된다.(n은 5이하의 자연수)
이를 이용해 중첩 반복문으로 코드를 설계하면 다음과 같다.

먼저, 줄의 갯수가 1개부터 5개까지 1개씩 증가하는 반복문을 작성하면 다음과 같다.

for(int line=1; line<=5; line++) {// 줄 수
		
}

다음으로 줄 수 만큼 별의 갯수를 출력하는 코드를 작성하면 다음과 같다.

for(int starCnt=1; starCnt<=line; starCnt++){
...// code
}

위의 코드는 줄 수 별 갯수가 1개부터 줄 갯수인line까지 반복하는 코드로, 줄 갯수가 3인 경우(세번째 줄) line=3이 되서 반복문 안에 있는 코드가 총 3번 반복하게 된다.

이를 이용해 줄 수 대로 별을 출력하는 코드는 다음과 같이 작성할 수 있다.

for(int line=1; line<=5; line++) {// 줄 수
		for(int starCnt=1; starCnt<=line; starCnt++){// 별 갯수
        	System.out.print("*");// 별 출력
	}
    System.out.print("\n");// 줄 넘김(엔터키)
}

output

*
**
***
****
*****

또한, 중괄호 때문에 가독성이 떨어질 수 있으므로, 위의 코드와 같이 반복문 안의 코드가 1줄 뿐인 경우는 아래와 같이 중괄호를 생략할 수 있다.

for(int line=1; line<=5; line++) {// 중괄호 생략 불가능(실행하는 코드가 한줄 이상임.) 
		for(int starCnt=1; starCnt<=line; starCnt++)// 중괄호 생략 가능
        	System.out.print("*");// 별 출력
	
    System.out.print("\n");// 줄 넘김(엔터키)
}

2. 실습

  • Q1

중첩 반복문을 이용해 짝수단인 2단, 4단, 6단, 8단만 출력하는 코드를 작성하시오.
단, 2단의 경우, 2*3까지만 출력하며, 4단의 경우 4*5까지만 출력, 6단의 경우 6*7까지만 출력, 8단의 경우 8*9까지 출력하도록 하시오.

  • Q2

중첩 반복문을 이용해 다음 별을 출력하시오.

  *
 ***
*****
  • Q3

중첩 반복문을 이용해 다음 별을 출력하시오.

  *
 ***
*****
 ***
  *
  • Q4

중첩 반복문을 이용해 다음 별을 출력하시오.

*****
 ***
  *
 ***
*****

고난도 문제

  • Q5

중첩 반복문을 이용해 다음 별을 출력하시오.

*     *
**   **
*** ***
*******
*** ***
**   **
*     *

Hint: 중간의 공백 갯수의 규칙을 확인하시오.

  • Q6

중첩 반복문을 이용해 다음 별을 출력하시오.

    *
   * *
  *   *
 *     *

Hint: 삼각형 내부의 공백 갯수의 규칙을 확인하시오.


  • A1

위 문제의 규칙은 다음과 같다.

  • 2, 4, 6, 8단을 출력하는 것으로, 앞의 곱하는 수가 2씩 증가한다.
  • 다음 곱하는 수는 3, 5, 7, 9까지 곱하는 것으로, "앞의 곱하는 수+1" 이 된다.

이를 이용해서 코드를 작성하면 다음과 같다.

code

public class Q1 {
	public static void main(String[] args) {
		
		int i, j;
		
		for(i=2; i<=8; i+=2) {// 2단씩 증가
			for(j=1; j<=i+1; j++) // 앞의 곱하는 수(i)+1 까지 곱함
				System.out.println(i + " x "+ j + " = " + i*j);
			
			System.out.print("\n");
		}
		
	}
}

output

2 x 1 = 2
2 x 2 = 4
2 x 3 = 6

4 x 1 = 4
4 x 2 = 8
4 x 3 = 12
4 x 4 = 16
4 x 5 = 20

6 x 1 = 6
6 x 2 = 12
6 x 3 = 18
6 x 4 = 24
6 x 5 = 30
6 x 6 = 36
6 x 7 = 42

8 x 1 = 8
8 x 2 = 16
8 x 3 = 24
8 x 4 = 32
8 x 5 = 40
8 x 6 = 48
8 x 7 = 56
8 x 8 = 64
8 x 9 = 72
  • A2

이번 문제의 별찍기의 규칙을 쉽게 알아보기 위해 표로 나타내면 다음과 같다.

위 그림을 보면 다음과 같은 배열이 보일 것이다.
첫번째 줄: 공백2개, 별 1개
두번째 줄: 공백1개, 별 3개
세번째 줄: 공백0개, 별 5개

이를 통해 줄 수가 증가함에 따라 공백의 갯수가 2개부터 시작해서 1개씩 줄어들고, 별의 갯수는 1개부터 2개씩 증가함을 알 수 있다.

조금 더 일반화 해서 줄의 갯수가 총 4개일 때는 다음과 같이 별이 찍힌다.

줄의 갯수가 총 4개일때 공백의 갯수는 3개부터 1개씩 줄어들고, 별의 갯수는 1개부터 2개씩 증가함을 알 수 있다.

즉, 줄의 총 갯수(높이)가 N인 경우 처음 공백의 갯수는 N-1부터 1개씩 줄어들며, 별의 갯수는 1개부터 2개씩 증가한다.
또한, 공백을 먼저 출력 후 별을 출력하는 방식으로 작성하는 방식으로 별을 찍을 수 있다.

이러한 규칙을 기반으로 코드를 작성하면 다음과 같다.

code

public class Q2 {
	public static void main(String[] args) {
		final int N=3;// 줄의 높이
		int starCnt, spaceCnt;// 별 갯수, 공백 갯수
		int i, j, k;
		
		starCnt=1;// 별 갯수는 1개부터
		spaceCnt=N-1;// 공백 갯수는 N-1부터
		
		for(i=0; i<N; i++) {
			
			for(j=0; j<spaceCnt; j++)// 공백 출력
				System.out.print(" ");
			
			for(k=0; k<starCnt; k++)// 별 출력
				System.out.print("*");
			
			System.out.println();
			starCnt+=2;// 별 갯수 2개 증가
			spaceCnt--;// 공백 갯수 1개 감소
		}
	}
}

output

  *
 ***
*****
  • A3

이번 문제의 별찍기 규칙을 찾기 위해 표를 그리면이번 문제의 별찍기의 규칙을 쉽게 알아보기 위해 표로 나타내면 다음과 같다.

또한 위 별찍기는 다음과 같이 두 부분으로 나눠서 나타낼 수 있다.

위의 빨간색 영역을 up pyramid 라고 하고, 아래 파란색 영역을 down pyramid라고 하자.
up pyramid의 경우 직전의 예제와 동일하므로 설명은 생략하도록 하고, down pyramid의 경우 공백의 갯수는 1개부터 시작해서 1개씩 증가하며, 별의 갯수는 3개부터 시작해서 2개씩 감소함을 알 수 있다.

이를 조금 더 확장해서 up pyramid 기준으로 높이가 4일때의 경우는 다음과 같다.

up pyramid 기준으로 높이가 4일 경우, down pyramid의 경우 다음과 같이 구성되 있다.
첫번째 줄: 공백 1개, 별 5개
두번째 줄: 공백 2개, 별 3개
세번째 줄: 공백 3개, 별 1개

즉, 공백의 갯수는 1개부터 1개씩 늘어나고, 별의 갯수는 up pyramid의 높이가 N일때 2*(N-1)-1개 부터 시작해서 2개씩 감소함을 알 수 있다. 또한, down pyramid의 높이는 up pyramid의 높이에서 1을 뺀 값과 같다.

이러한 규칙을 이용해 코드를 작성하면 다음과 같다.

code

public class Q3 {
	public static void main(String[] args) {
		final int N=3;// up pyramid 높이
		int starCnt, spaceCnt;// 별 갯수, 공백 갯수
		int i, j, k;
		
		/*up pyramid*/
		starCnt=1;// 별 갯수는 1개부터
		spaceCnt=N-1;// 공백 갯수는 N-1부터
		for(i=0; i<N; i++) {
			for(j=0; j<spaceCnt; j++)// 공백 출력
				System.out.print(" ");
			
			for(k=0; k<starCnt; k++)// 별 출력
				System.out.print("*");
			
			System.out.println();
			starCnt+=2;// 별 갯수 2개 증가
			spaceCnt--;// 공백 갯수 1개 감소
		}
		
		/*down pyramid*/
		starCnt=2*(N-1)-1;
		spaceCnt=1;
		for(i=0; i<N-1; i++) {
			for(j=0; j<spaceCnt; j++)// 공백 출력
				System.out.print(" ");
			
			for(k=0; k<starCnt; k++)// 별 출력
				System.out.print("*");
			
			System.out.println();
			starCnt-=2;// 별 갯수 2개 김소
			spaceCnt++;// 공백 갯수 1개 증가
		}
	}
}

output

  *
 ***
*****
 ***
  *
  • A4

이번 문제의 별찍기 규칙을 찾기 위해 표를 그리면 다음과 같다.

보다 직관적인 이해를 위해 영역을 나누면 다음과 같다.

표를 보면 알 수 있듯이 직전 예제에서 본 바와 같은 down pyramid와 up pyramid로 구성됬음을 알 수 있다. 물론, up pyramid의 경우 완전한 up pyramid가 아닌 별의 갯수가 3개부터 시작하는 up pyramid이다.

이를 조금 더 확장해 down pyramid 기준으로 높이가 4인 별찍기를 나타내면 다음과 같다.

위 표를 보면 down pyramid의 별의 갯수는 7이며, up pyramid의 경우 역시 별의 갯수가 3개부터 시작하며, up pyramid의 높이는 3임을 알 수 있다.

이를 높이가 3인 경우와 비교했을때 down pyramid의 경우 처음 별의 갯수는 높이가 N일때 2N-1개부터 시작해 2개씩 감소하고, 공백의 갯수는 0개부터 시작해 1개씩 증가함을 알 수 있다.

또한, up pyramid의 경우 별의 갯수가 3개부터 시작해 2개씩 증가하며, 공백의 갯수는 N-2개 부터 시작해 1개씩 감소함을 알 수 있다(앞전에 예제에서 피라미드의 공백 수는 N-1개부터 시작함을 통해 유추할 수 있다).
또한, up pyramid의 높이는 N-1이다.

이러한 규칙을 이용해 코드를 작성하면 다음과 같다.

code

public class Q4 {
	public static void main(String[] args) {
		final int N=3;// up pyramid 기준 높이
		int i, j, k;
		int starCnt, spaceCnt;
		
		/*down pyramid*/
		starCnt=(2*N)-1;
		spaceCnt=0;
		for(i=0; i<N; i++) {// down pyramid 높이
			for(j=0; j<spaceCnt; j++)// 공백 출력
				System.out.print(" ");
			
			for(k=0; k<starCnt; k++)// 별 출력
				System.out.print("*");
			
			System.out.println();
			starCnt-=2;// 별 갯수 2개 김소
			spaceCnt++;// 공백 갯수 1개 증가
		}
		
		/*up pyramid*/
		starCnt=3;// 별 갯수는 3개부터
		spaceCnt=N-2;// 공백 갯수는 N-2부터
		for(i=0; i<N-1; i++) {// up pyramid 높이
			for(j=0; j<spaceCnt; j++)// 공백 출력
				System.out.print(" ");
			
			for(k=0; k<starCnt; k++)// 별 출력
				System.out.print("*");
			
			System.out.println();
			starCnt+=2;// 별 갯수 2개 증가
			spaceCnt--;// 공백 갯수 1개 감소
		}
	}
}

output

*****
 ***
  *
 ***
*****
  • A5

이번 문제의 별찍기 규칙을 찾기 위해 표를 그리면 다음과 같다.

또한, 영역을 나눠 아래 표를 보면 피라미드가 좌우 및 상하 대칭으로 있음을 알 수 있다.

이때, 아래 그림과 같이 가운데 줄의 별의 수를 높이 N이라 할때 각 줄의 공백과 별의 갯수는 다음과 같다.

첫번째 줄: 별 갯수 2개, 공백 갯수 5개
두번째 줄: 별 갯수 4개, 공백 갯수 3개
세번째 줄: 별 갯수 6개, 공백 갯수 1개
네번째 줄: 별 갯수 7개, 공백 갯수 0개
다섯번째 줄: 별 갯수 6개, 공백 갯수 1개
여섯번째 줄: 별 갯수 4개, 공백 갯수 3개
일곱번째 줄: 별 갯수 2개, 공백 갯수 5개

이때, 좌우 대칭이기 때문에 별의 갯수가 2개씩 증가하고, 공백의 갯수는 2개씩 감소함을 알 수 있다.
또한 대칭점인 가운데 줄(4번째 줄)을 기준으로 윗부분의 높이는 4칸, 아랫부분의 높이는 3임을 알 수 있다.
또한 첫 줄의 별의 갯수는 2, 공백의 갯수는 5임을 알 수 있다.

조금 더 확장해 높이 N이 5인 리본을 그리면 다음과 같다.

대칭점인 가운데 줄(5번째 줄)을 기준으로 윗부분의 높이는 5이며, 아랫부분의 높이는 4임을 통해 윗 부분의 높이는 N, 아랫부분의 높이는 N-1임을 알 수 있다.

다음으로, 상하 대칭에서의 윗부분의 규칙을 찾으면 다음과 같다.

높이 N=5일때의 리본 역시 첫번째 별의 갯수는 2개이며, 공백의 갯수는 7개이다. 즉, N이 증가함에 따라 첫 줄의 공백의 갯수는 2N 만큼 증가함을 알 수 있다.
이를 통해 방정식을 세우면
2*4+x=5,
2*5+x=7
즉, x=3이므로, 첫번째 줄의 공백의 갯수는 2N-3 개임을 알 수 있으며, 줄이 증가함에 따라 공백의 갯수는 2개씩 감소한다.
또한, 상하대칭에서 마지막 부분(N번째 줄)의 경우 대칭이 아니며, 별의 갯수는 2N-1개 이다.

마지막으로, 상하 대칭에서의 아랫부분의 규칙을 찾으면 다음과 같다.
공백의 갯수는 동일하게 1개부터 시작해 높이 N-1까지 2개씩 증가하며, 아랫부분의 별의 갯수는 높이가 4일때 6, 높이가 5일때는 8임을 통해 2(N-1)임을 알 수 있다.

동시에 좌우대칭이므로, 별을 출력할 때는 별의 갯수를 n/2 만큼 출력하고, 공백을 출력한 다음 다시 나머지 별의 갯수인 n/2 만큼 출력하는 방식을 사용해야 한다.

이러한 규칙을 이용해 코드를 작성하면 다음과 같다.

code

public class Q5 {
	public static void main(String[] args) {
		final int N=4;
		int starCnt, spaceCnt;
		int i, j;
		
		/*상하대칭 윗부분*/
		starCnt=2;
		spaceCnt=(2*N)-3;
		for(i=0; i<N-1; i++) {
			
			for(j=0; j<(starCnt/2); j++)// 별 출력
				System.out.print("*");
			
			for(j=0; j<spaceCnt; j++)// 공백 출력
				System.out.print(" ");
			
			for(j=0; j<(starCnt/2); j++)// 별 출력
				System.out.print("*");
			
			System.out.println();
			
			spaceCnt-=2;// 공백 갯수 2 감소
			starCnt+=2;// 별 갯수 2 증가
		}
		
		starCnt=(2*N)-1;// 대칭점 별 갯수
		for(j=0; j<starCnt; j++)// 별 출력
			System.out.print("*");
		System.out.println();
		
		/*상하대칭 아렛부분*/
		starCnt=2*(N-1);
		spaceCnt=1;
		for(i=0; i<N-1; i++) {
			
			for(j=0; j<(starCnt/2); j++)// 별 출력
				System.out.print("*");
			
			for(j=0; j<spaceCnt; j++)// 공백 출력
				System.out.print(" ");
			
			for(j=0; j<(starCnt/2); j++)// 별 출력
				System.out.print("*");
			
			System.out.println();
			
			spaceCnt+=2;// 공백 갯수 2 감소
			starCnt-=2;// 별 갯수 2 증가
		}
	}
}

output

*     *
**   **
*** ***
*******
*** ***
**   **
*     *
  • A6

이번 문제의 별찍기 규칙을 찾기 위해 표를 그리면 다음과 같다.

높이N=5인 트리모양의 별찍기에서 줄 별로 공백과 별의 규칙은 다음과 같다.

첫번째줄: 공백 4칸 후 별 1개
두번째줄: 공백 3칸 후 별 1개, 공백 1칸 후 별 1개
세번째줄: 공백 2칸 후 별 1개, 공백 3칸 후 별 1개
네번째줄: 공백 1칸 후 별 1개, 공백 5칸 후 별 1개
다섯번째줄: 공백 0칸 후 별 1개, 공백 7칸 후 별 1개

즉, 첫번째 줄을 제외하고 모두 공백 후 별을 찍고, 그 다음 다시 공백 후 별을 찍는 방식이다.

이를 조금 더 확장해서 높이 N=7일때의 트리모양을 그리면 다음과 같다.

높이N=7인 트리모양의 별찍기에서 줄 별로 공백과 별의 규칙은 다음과 같다.

첫번째줄: 공백 6칸 후 별 1개
두번째줄: 공백 5칸 후 별 1개, 공백 1칸 후 별 1개
세번째줄: 공백 4칸 후 별 1개, 공백 3칸 후 별 1개
네번째줄: 공백 3칸 후 별 1개, 공백 5칸 후 별 1개
다섯번째줄: 공백 2칸 후 별 1개, 공백 7칸 후 별 1개
여섯번째줄: 공백 1칸 후 별 1개, 공백 9칸 후 별 1개
일곱번째줄: 공백 0칸 후 별 1개, 공백 11칸 후 별 1개

N=7인 트리 역시 첫번째 줄은 공백 후 별을 찍고, 그 다음줄 부터는 공백 후 별을 찍고 다시 공백 후 별을 찍는 방식이다.

또한, N=5인 트리에서 첫번째 줄의 공백 갯수는 4칸, N=7인 트리에서의 첫번째 줄 공백 갯수가 6칸임을 볼때 처음 공백 시작 갯수는 N-1임을 유추할 수 있다.

또한, 첫번째 공백의 경우 줄이 늘어남에 따라 1칸씩 줄어들고, 두번째 공백의 1칸부터 시작해 2칸씩 늘어남을 알 수 있다.

이러한 규칙을 이용해 코드를 작성하면 다음과 같다.

code

public class Q6 {
	public static void main(String[] args) {
		final int N=5;// 높이
		int firstSpace, secondSpace;// 첫번째 공백, 두번째 공백
		int i, j;
		
		/*첫번째 줄*/
		firstSpace=N-1;
		for(i=0; i<firstSpace; i++) {
			System.out.print(" ");
		}
		System.out.println("*");
		
		/*두번째 줄 이상*/
		firstSpace--;
		secondSpace=1;// 두번째 공백 크기 설정
		for(i=0; i<N-1; i++) {// 천번째 줄에서 한번 출력 했으므로, N-1만큼만 반복
			
			for(j=0; j<firstSpace; j++)// 첫번째 공백
				System.out.print(" ");
			
			System.out.print("*");// 첫번째 별
			
			for(j=0; j<secondSpace; j++)// 두번째 공백
				System.out.print(" ");
			
			System.out.println("*");// 두번째 별
			
			firstSpace--;// 첫번째 공백 감소
			secondSpace+=2;// 두번째 공백 증가
		}
		
	}
}

output

    *
   * *
  *   *
 *     *
*       *

대부분의 코딩은 이번에 풀었던 문제와 같이 규칙을 찾아내는 것이 중요하다.
이러한 규칙은 단순한 패턴으로 구성된 경우도 있으나, 수학적, 논리적인 규칙이 존재하는 경우 역시 많이 존재한다. 이러한 규칙을 알고리즘이라 하며, 이러한 알고리즘의 해석 능력이 개발자의 경쟁력이 되곤 한다.

이러한 알고리즘을 잘 설계하고, 해석하기 위해서는 문제를 바라볼때 "왜 이러한 값이 주어졌을까?" 라는 생각을 하면서 규칙을 찾고, 규칙을 찾으려는 습관과 더불어 많이 문제를 접하면서 수학적인 사고능력을 기르는 것이 중요하다.

위 주소에서 code를 다운로드 받아 eclipse로 직접 정답 확인이 가능하다.
https://github.com/isaiahIM/java_basic/tree/main/nested%20loop

profile
나는 생각한다. 고로 나는 코딩한다.

0개의 댓글