[JavaScript] 중첩 반복문(별찍기)

중첩 반복문의 별찍기 예제이다. 알고리즘 기초 문제로 자주 등장하는 예제중 하나이다. 우선 하단의 별모양으로 찍어보자

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

나는 프로그래밍을 처음 배울때 아래처럼 코드를 작성했었다.

var star = '';
for (var i = 0; i < 10; i++) {
    star += '*';
    console.log(star);
}

*이 저장될 star를 선언한뒤 하나씩 *을 한번씩 추가한뒤 반복문이 끝나지 않고 바로 콘솔창으로 출력이 된다. 콘솔창에 10번 출력되면 되는줄 알고 반복문을 왜 중첩으로 사용해야 되지? 라는 짧은 생각을 했었던 적이 있었다.
화면에 출력하는 것도 함수를 호출하는 것이기 때문에 10번 출력한다는 것은 그만큼 비효율적이다. 반복문이 돌아갈때마다 출력하는 것이 아닌, 구해진 값을 담아 한번에 출력해야 좀 더 효율적인 방법이라 할 수 있다. 이렇게 하기 위해선 반복문이 중첩으로 사용되어야 한다.

기본 별찍기

var star = '';
for (var i = 0; i < 10; i++) {
    for (var j = 0; j <= i; j++) {
        star += '*';
    }
    star += '\n';
}
console.log(star);

코드를 살펴 보자

외부 반복문에서 i값이 0인 상태로 내부 반복문으로 들어 간다. j가 0으로 선언되고 j와 i를 비교한다. j와 i값은 0과 0으로 같기 때문에 star에 *이 한번 대입되고 내부 반복문을 빠져 나온뒤 줄바꿈문자인 \n을 star에 대입시킨다. 외부 반복문이 다시 실행된다. i값이 +1 되어 1인 상태에서 다시 내부함수로 들어간다. 내부반복문의 조건은 j값이 i보다 같거나 클 때 실행이 된다. j값은 0으로 초기화되었기 때문에 i값이 1이므로 star에 *을 두번 대입하고 내부반복문을 빠져나오게 되고 다시 \n을 대입하여 줄바꿈이 이루어진다.

이 과정을 반복하여 열번째 *을 대입하고 마지막으로 결과 값을 콘솔창에 뿌리게 된다. 콘솔창을 보면 제대로 출력된 결과물을 볼 수 있다.

두개씩 별찍기

여기서 응용을 하여 아래 모양으로 출력해 보자

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

별이 2개씩 추가되었다. 외부반복문의 i값이 0일때 별을 한번 찍고, 이후에는 j값이 2의 배수 일때만 내부 반복문을 실행하는 조건을 달아주면 된다.

var star = '';
for (var i = 0; i < 10; i++) {
    for (var j = 0; j <= (i * 2); j++) {
        star += '*';
    }
    star += '\n';
}
console.log(star);

정상적으로 출력되는걸 확인할 수 있다.

역삼각형 별찍기

아래처럼 역삼각형으로 나타낼려면 어떻게 되는지 알아보자

***********
**********
*********
********
*******
******
*****
****
***
**
*
var star = '';
for (var i = 10; i >= 0; i--) {
    for (var j = 0; j <= i; j++) {
        star += '*';
    }
    star += '\n';
}
console.log(star);

i값을 10으로 설정한 뒤 i값이 0과 같아질때까지 i값을 빼주면 된다. 정상적으로 코드가 출력되는걸 확인할 수 있다.

가운데 정렬 삼각형 별찍기

가운데 정렬 삼각형을 만들어 보자

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

5줄로 만들어진 삼각형 이다. 차근차근 살펴 보자, 왼쪽부터 공백이 들어가고 별은 처음 한번 찍힌 뒤 2개씩 늘어나면서 찍힌다. 이제 코드를 확인해 보자

var star = '';
for (var i = 0; i < 5; i++) {
    for (var j = 4; j > i; j--) {
        star += ' ';
    }
    for (var k = 0; k <= (i * 2); k++) {
        star += '*';
    }
    star += '\n';
}
console.log(star);

별과 공백이 대입될 star를 선언한 뒤 외부 반복문이 실행 된다. 5줄인 삼각형을 만들계획이니 외부 반복문은 5번만 실행해야 된다. i값이 5보다 작을 때 까지만 조건을 달아주고 내부 반복문으로 들어가고, 공백이 들어갈 반복문이 첫번째로 나온다. 5줄인 삼각형이니 공백은 4칸 대입 다음에 별이 한개 대입되고, 다음에는 공백 3칸에 별 세개, 이런식으로 반복되서 마지막 5줄째에는 공백이 없고 별만 9개가 대입되도록 짜면 될 것이다. 첫번째 내부 반복문에서 공백을 star에 4번 대입하고 빠져 나온다. 두번째 내부 반복문에서는 처음 별 한개를 대입한 뒤 이후에는 2의 배수만큼 별을 대입한다. 두번째 내부 반복문을 빠져나오면 줄바꿈이 대입되고, 외부 반복문이 다섯번 반복되면 이제 콘솔창에 결과값을 출력하게 된다.

다이아몬드 별찍기

이제 위에 예제를 응용하여 다이아몬드 형태를 만들어 보도록 하자, 복잡한 예제인 만큼 차근 차근 해석해 보겠다.

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

몇줄인지 보면 아홉줄이다. 9번 실행되는 반복문을 먼저 선언해 주자

var star = '';
for (var i = 0; i < 9; i++) {

}

다이아몬드 형태는 별이 다섯번째 줄까지 증가하다가 그 다음부터는 감소한다. i값이 4가 될 때까지만 별을 증가시켜 주는 조건문을 달고 내부 반복문을 선언해 주자

var star = '';
for (var i = 0; i < 9; i++) {
    if (i < 5) {
        for (var j = 4; j > i; j--) {
            star += ' ';
        }
        for (var k = 0; k <= i * 2; k++) {
            star += '*';
        }
        star += '\n';
    }
}
console.log(star);
    *
   ***
  *****
 *******
*********

위처럼 제대로 출력된다. 이전 예제에서 해봤기 때문에 어렵지 않게 작성할 수 있다. 이제 i값이 5가되면 별이 감소하는 반복문을 추가한다. 공백을 먼저 넣을 것이다. 눈으로 확인하기 쉽게 우선 공백을 - 로 표기하겠다.

var star = '';
for (var i = 0; i < 9; i++) {
    if (i < 5) {
        for (var j = 4; j > i; j--) {
            star += ' ';
        }
        for (var k = 0; k <= i * 2; k++) {
            star += '*';
        }
        star += '\n';
    } else {
        for (var j = 4; j < i; j++) {
            star += '-';
        }
        star += '\n';
    }
}
console.log(star);

i값이 4까지만 첫번째 조건문이 실행되고 i값이 5부터는 아래 조건문이 실행된다. 2번째 조건문 반복문을 만나서 j와 i값을 비교한다. j는 4로 선언되고 i는 5 이다. j는 i보다 작다. 참이다. 공백이 한번 찍히고 다시 돌면서 비교를 한다. j는 i와 같은 값인 5가 된다. 거짓이다. 반복문을 빠져나오고 줄바꿈을 한뒤 다시 외부 반복문이 i값을 증감 한다. 이 과정을 반복하면서 아래 모양처럼 출력된다.

    *
   ***
  *****
 *******
*********
-
--
---
----

이제 - 을 공백처리 한 후 별을 찍는 반복문을 추가 해 보자

var star = '';
for (var i = 0; i < 9; i++) {
    if (i < 5) {
        for (var j = 4; j > i; j--) {
            star += ' ';
        }
        for (var k = 0; k <= i * 2; k++) {
            star += '*';
        }
        star += '\n';
    } else {
        for (var j = 4; j < i; j++) {
            star += ' ';
        }
        for (var k = 9; k > i; k--) {
            star += '*';
        }
        star += '\n';
    }
}
console.log(star);

여기서 좀 복잡해진다. 우선 별 반쪽만 찍어보도록 해보자

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

아래 조건의 반복문은 i가 5부터 8까지만 4번 실행된다. i값이 5일때 k값과 비교를 한다. k는 9이므로 참이다. 별을 한번 찍고 k값은 차례로 내려간다. k값이 9, 8, 7, 6이 될때까지 별을 네번 찍고 반복문을 빠져 나온다. 이 과정을 거쳐 위 모양처럼 별이 출력된다. 하지만 별은 2개씩 찍혀야 된다. 조건문에 2를 곱해보자

var star = '';
for (var i = 0; i < 9; i++) {
    if (i < 5) {
        for (var j = 4; j > i; j--) {
            star += ' ';
        }
        for (var k = 0; k <= i * 2; k++) {
            star += '*';
        }
        star += '\n';
    } else {
        for (var j = 4; j < i; j++) {
            star += ' ';
        }
        for (var k = 9; k > i * 2; k--) {
            star += '*';
        }
        star += '\n';
    }
}
console.log(star);
    *
   ***
  *****
 *******
*********
 
  
   
    

출력되지 않는다. 이유는 i값이 배가 되어 k값보다 훨 씬 커지기 때문이다. 처음 비교할때 k값은 9인데 i값은 10이기 때문이다. i값의 최대치는 8인데 배가 되니 16보다 큰 수가 k값으로 대입되어야 한다. 17을 대입해 주자

var star = '';
for (var i = 0; i < 9; i++) {
    if (i < 5) {
        for (var j = 4; j > i; j--) {
            star += ' ';
        }
        for (var k = 0; k <= i * 2; k++) {
            star += '*';
        }
        star += '\n';
    } else {
        for (var j = 4; j < i; j++) {
            star += ' ';
        }
        for (var k = 17; k > i * 2; k--) {
            star += '*';
        }
        star += '\n';
    }
}
console.log(star);

k값은 17, i는 5 * 2 = 10 이다. 참이다. 별을 한번 찍고, 다시 비교, 16 > 10 이다. 이과정을 네번 반복하고 계속 찍어 내려간다. 마지막 i값이 8일때 k는 17 i는 8*2 = 16 참이다. 다시 돌아서 k–은 16 이다. 16 < 16 거짓이다. 반복문을 빠져 나온다. 제대로 출력되는 것을 확인할 수 있다.

updated_at 21-02-2018