F.R.I.D.A.Y.

C: 숫자 지그재그로 출력하기 본문

DEV/C C++

C: 숫자 지그재그로 출력하기

F.R.I.D.A.Y. 2020. 7. 24. 04:44
반응형

 위 이미지처럼 종종 숫자를 순서대로 나열하는 것이 아니라 지그재그로 출력하도록 하는 문제가 있습니다. 이 문제를 어떻게 해결하는지 알아보겠습니다.


수식 찾기

 이미지의 숫자에 대한 정규식을 찾아보죠.

 1, 3, 5번째 라인의 경우 x좌표[# 편하게 이야기해서 x좌표지 실제로는 column. 열이 되겠네요.]의 증가와 따라가는데 반해 2, 4번째 라인은 x좌표에 역행하는 것을 알 수 있습니다.

 마구잡이로 식이 변경되는 것이 아니라 홀수 라인은 정방향, 짝수 라인은 역방향임을 알 수 있습니다. 따라서 우리는 아래처럼 수식을 만들 수 있겠네요.

홀수 라인 (현재 라인 번호 - 1) * 5 + (현재 x좌표)
짝수 라인 (현재 라인 번호) * 5 - (현재 x좌표 - 1)

 

 프로그램에서는 0부터 시작합니다. 따라서 1, 3, 5는 0, 2, 4로. 2, 4는 1, 3으로 변경되겠군요. 그럼 다시 정리해봅니다.

홀수 라인(프로그래밍 적용) (현재 라인 번호) * 5 + (현재 x좌표 + 1)
짝수 라인(프로그래밍 적용) (현재 라인 번호 + 1) * 5 - (현재 x좌표)

 

코드 작성

#include <stdio.h>

int main(void) {
	int a[5][5] = { 0 };
	for (int y = 0; y < 5; ++y) {
		if (y % 2 == 0) { // 0, 2, 4 (1, 3, 5)
			for (int x = 0; x < 5; ++x) {
				a[y][x] = y * 5 + x + 1;
			}
		}
		else { // 1, 3 (2, 4)
			for (int x = 0; x < 5; ++x) {
				a[y][x] = (y + 1) * 5 - x;
			}
		}
	}

	for (int y = 0; y < 5; ++y) {
		for (int x = 0; x < 5; ++x) {
			printf("%3d ", a[y][x]);
		}
		printf("\n");
	}
	
}

 이 코드는 최상단 이미지처럼 작동합니다. 그런데 우리는 이 코드를 최적화할 수 있습니다.

 

Optimization.

 분기 명령은 속도를 느리게 하는 원인 중 하나로 꼽힙니다. 우리는 생각을 조금 해서 분기 명령인 if를 사용하지 않고 동일한 명령을 수행하는 코드를 구성해보겠습니다.

#include <stdio.h>

int main(void) {
	int a[5][5] = { 0 };
	short interval[2] = { 1, -1 };
	for (int y = 0; y < 5; ++y) {
		for (int x = 0; x < 5; ++x) {
			a[y][x] = (y + y % 2) * 5 + (x * interval[y % 2] + ((y+1) % 2));
		}
	}

	for (int y = 0; y < 5; ++y) {
		for (int x = 0; x < 5; ++x) {
			printf("%3d ", a[y][x]);
		}
		printf("\n");
	}
	
}

 핵심은 8번 라인입니다. 하나하나 풀어보겠습니다.

(y + y % 2) * 5

 y의 값과 y를 2로 나눈 나머지를 더한 값을 5로 곱합니다. 0, 2, 4번 정방향 라인의 경우 나머지가 0이므로 더하지 않습니다. 1, 3번 라인은 역방향이므로 나머지 1을 더합니다. 따라서 분기 명령이 있는 코드의 수식 두 개에 모두 적합합니다.

 

(x * interval[y % 2] + ((y+1) % 2));

 x의 값에 interval[y % 2]에 해당하는 값을 곱합니다. interval 배열은 0번 1번 인덱스에 각각 1과 -1을 가지고 있습니다. 이는 분기 명령이 포함된 코드에서 부호가 서로 반대인 것을 고려해 부호 변경을 위해 작성되었습니다.

 

 분기 명령에서 정방향 라인은 최종 값에 1을 더해야 하고, 역방향 라인은 최종 값에 조작을 가해서는 안됩니다.[# 시작이 0부터이기 때문] 정방향은 더해야 하는데 나머지가 0이고, 역방향은 더하지 않아야 하는데 나머지가 1입니다. 따라서 라인 넘버에 1 더한 값을 2로 나누어 더해줍니다. 그렇게 되면 정방향 0, 2, 4번 라인은 연산 시 [1, 3, 5] % 2로 나머지가 1, 역방향 1, 3번 라인은 [2, 4] % 2로 나머지가 0이 됩니다. 따라서 분기 명령이 존재하는 기존 코드와 동일한 작업을 분기 명령 없이 마칠 수 있습니다.


 몇 가지만 조작하면 정방항 라인과 역방향 라인을 서로 바꿀 수 있습니다. 한번 도전해보세요!

 

# index

728x90
반응형

'DEV > C C++' 카테고리의 다른 글

C: 반복문  (0) 2020.09.07
C: volatile 키워드  (0) 2020.08.22
프로그램에 일상을 더하다: 여러 항목 정렬하기  (0) 2020.03.19
XOR: 배타적 논리합  (0) 2020.02.28
부동소수점  (2) 2020.02.22
Comments