공부

스파이럴(달팽이) 배열 구현하기 - switch/case 방향 전환 방식

CodingNabi 2026. 7. 8. 19:39

C로 5x5 스파이럴 배열을 채우는 문제를 여러 방식으로 구현해보면서, 각 방식의 원리와 장단점을 정리해본다. 첫 번째로 다룰 방식은 switch문으로 방향을 관리하는 방식이다.(처음 문제를 보고 내가 푼 방식이라 많이 와일드 하다. 나머지 3개는 교재참고, 다른 자료를 참고한 방식이다.)

문제 정의

5x5 정수 배열을 아래처럼 시계방향 나선형으로 1부터 25까지 채우는 게 목표다.

1   2   3   4    5
16  17  18  19   6
15  24  25  20   7
14  23  22  21   8
13  12  11  10   9

 

방식 설명

핵심 아이디어는 간단하다. 한 방향으로 갈 수 있는 데까지 가고, 막히면(이미 채워진 칸을 만나면) 다음 방향으로 90도 회전한다.

방향은 4가지뿐이므로 enu으로 정의하고, switch로 지금 어느 방향으로 가는 중인지를 분기한다.

각 방향은 for 문 하나로 표현되고, 방향이 바뀔때마다 changeFlag를 다음 방향으로 갱신한다.

이미 채워진 초깃값이 0이라는 점을 이용해 arr[y][x] == 0으로 값을 채울지, 아니면 루프를 종료하고 다음 분기로 넘어갈지 판단한다.

void fillSpiralBySwitch(int arr[SIZE][SIZE]) {
	enum {
		GORIGHT,
		DOWN,
		GOLEFT,
		UP
	};

	int changeFlag = GORIGHT;
	int value = 0;
	int x = 0;
	int y = 0;
	while (value < SIZE * SIZE) {
		switch (changeFlag) {
		case GORIGHT: {
			for (x; x < SIZE && y >= 0 && y < SIZE; x++) {
				if (arr[y][x] == 0)
					arr[y][x] = ++value;
				else
					break;
			}
			--x;
			++y;
			changeFlag = DOWN;
			break;
		}
		case DOWN: {
			for (y; x >= 0 && x < SIZE && y < SIZE; y++) {
				if (arr[y][x] == 0)
					arr[y][x] = ++value;
				else
					break;
			}
			--y;
			--x;
			changeFlag = GOLEFT;
			break;
		}
		case GOLEFT: {
			for (x; x >= 0 && y >= 0 && y < SIZE; x--) {
				if (arr[y][x] == 0)
					arr[y][x] = ++value;
				else
					break;
			}
			++x;
			--y;
			changeFlag = UP;
			break;
		}
		case UP: {
			for (y; y >= 0 && x >= 0 && x < SIZE; y--) {
				if (arr[y][x] == 0)
					arr[y][x] = ++value;
				else
					break;
			}
			++y;
			++x;
			changeFlag = GORIGHT;
			break;
		}
		}
	}
}

 

그림

 

과정

 

1단계 GORIGHT : (0,0) → (1,0) → (2,0) → (3,0) → (4,0)     [1~5 채움]
                                                     for 종료 시 x=5, 보정 --x → x=4
                                                     ++y → y=1
                                                     changeFlag = DOWN

2단계 DOWN    : (4,1) → (4,2) → (4,3) → (4,4)             [6~9 채움]
                                                     for 종료 시 y=5, 보정 --y → y=4
                                                     --x → x=3
                                                     changeFlag = GOLEFT

3단계 GOLEFT  : (3,4) → (2,4) → (1,4) → (0,4)             [10~13 채움]
                                                     for 종료 시 x=-1, 보정 ++x → x=0
                                                     --y → y=3
                                                     changeFlag = UP

4단계 UP      : (0,3) → (0,2) → (0,1)                     [14~16 채움]
                (0,0)은 이미 채워져 있어 break
                                                     for 종료 시 y=0, 보정 ++y → y=1
                                                     ++x → x=1
                                                     changeFlag = GORIGHT

5단계 GORIGHT : (1,1) → (2,1) → (3,1)                     [17~19 채움]
                (4,1)은 이미 채워져 있어 break
                ... (이하 반복, 안쪽으로 계속 좁혀짐)

 

특징

장점

- 가독성이 나쁘지 않다 : 어느 방향으로 가는지 코드 구조에 드러난다. case만 따라가다 보면 로직 전체를 이해할 수 있다.

- 디버깅 용이 : 방향별로 로직이 분리되어 있어, 특정 방향에서 생기는 문제가 생기면 그 case만 보면 된다.

- 홀수/짝수 크기 지원 : 이미 채워진 칸인지를 값으로 직접 판단하기 때문에, 배열 크기의 홀짝 여부에 로직이 의존하지 않는다.

- 직사각형 확장이 비교적 쉽다 : x, y의 이동 범위가 이미 분리되어 있어서 가로세로 크기를 다르게 둬도 구조 자체는 크게 바뀌지 않는다.

단점

- 코드가 길다 : 방향이 4개면 case도 4개, 로직도 4개가 필요하다.

- for문에 인덱스 보정이 필요하다 : 각 방향의 for문이 조건을 만족하지 못하는 시점(예: x == SIZE)에 끝나기 때문에, case 끝마다 x,y값을 보정하는 보정 코드가 따라붙는다.

- 배열 값에 의존한다 : "0이면 채워지지 않은 칸"이라는 전제로 동작하기 때문에, 채우는 값 자체가 0이거나, 이미 채워진 값을 다시 채우는 경우 동작하지 않는다.