[SBS게임아카데미] 1인개발 프로그래밍 (C#, 유니티)

[6] C# 배열과 정렬 (SBS게임아카데미 5일차_230715_토)

개발린마케터 2023. 7. 17. 19:00
반응형

[오름차순 정렬]

            int[] arr = new int[] { 11, 22, 5, 1, 55, 84, 3, 9, 2, 36, 67, 42 };

            Console.WriteLine("정렬 전");
            foreach (int i in arr) Console.WriteLine(i);

            Console.WriteLine("정렬 후");

            for (int i = 0; i < arr.Length; i++)
            {
                for (int j = i + 1; j < arr.Length; j++)
                {
                    if (arr[i] > arr[j])  
                    {
                        //스왑 swap
                        int temp = arr[i];
                        arr[i] = arr[j];
                        arr[j] = temp;
                    }
                }
                Console.WriteLine(arr[i]);
            }

여기서는 정렬을 하는 방식과 스왑의 개념에 대해서 이해가 필요하다. 

제일 첫 숫자부터 시작해서 하나씩 하나씩 그 다음 숫자와 비교해가면서 i가 j보다 크면 

임시로 i를 옮겨놓고, i에 j를 넣고, j에 임시로 옮겨놨던 애를 가져온다.

이런 식으로 하나하나 스왑해서 바꿔가면서 정렬을 하는 형태였다. 

 

그냥 숫자를 정렬한다는 개념이 머릿속으로는 그냥 직관적으로 주르륵 배치하는 느낌이었는데, 

이렇게 컴퓨터가 이해할 수 있는 언어로 풀어낸다는 건 차례차례 순서도로 찍어주는 느낌이다.

손으로 하나하나 쓰고 머리로 시뮬레이션할 때는 한참 걸렸는데 Ctrl + F5 누르면 순식간!

[내림차순 정렬]

혹시 눈치챘는지 모르겠지만 가운데 서식 하나만 바꾸면 오름차순이 내림차순이 된다. 

 

if (arr[i] > arr[j])  //내림차순은 '>' 을 '<'로 등호만 바꾸면 된다

 

 

[정렬의 또 다른 방법 "Array.Sort", "Array.Reverse"]

위에서 한참 길고 어렵게 코드를 써 넣어서 정렬을 했는데 

이렇게 간단히 되는 방법도 있었다. 

 

Array.Sort는 오름차순으로만 정리된다. 

그래서 내림차순으로 할 때는?

Array.Reverse로 뒤집어주면 된다. 

            int[] arr2 = { 66, 3, 5, 88, 31, 83, 2, 9, 16, 54 };
            foreach (int i in arr2) { Console.WriteLine(i); }

            Console.WriteLine("정렬 후");
            Array.Sort(arr2);
            foreach (int i in arr2) { Console.WriteLine(i); }

            Array.Reverse(arr2);
            Console.WriteLine("내림차순");
            foreach (int i in arr2) { Console.WriteLine(i); }

이렇게 간단히 된다!

 

[다차원 배열]

 - 2차원 배열: 가로 x 세로

 - 3차원 배열: 가로 x 세로 x 높이

요런 개념이라고 생각하면 된다. 

 

3행, 4열로 랜덤한 숫자를 배열해보자. 

            int[,] arr3 = new int[3, 4];

            Random ran = new Random();

            for (int i = 0; i < arr3.GetLength(0); i++)
            {
                for (int j = 0; j < arr3.GetLength(1); j++)
                {
                    Console.WriteLine("arr3[{0},{1}]: {2}", i, j, arr3[i, j] = ran.Next(0, 100));
                }
                Console.WriteLine("");

랜덤하게 잘 배치가 되었다!

[배열의 크기(데이터 개수)와 행의 길이(데이터 개수)]

int[,] arr4 = new int[4, 4]
            {
                { 1,2,3,4},
                { 5,6,7,8},
                { 9,10,11,12},
                { 13,14,15,16}
            };

2차원 배열로 4 x 4의 배열을 정의했다. 

위와 같은 배열이 있다고 했을 때 전체 데이터의 크기와 행의 길이를 각각 구해보겠다.

+전체 데이터를 호출해서 확인해보겠다.

            int[,] arr4 = new int[4, 4]
            {
                { 1,2,3,4},
                { 5,6,7,8},
                { 9,10,11,12},
                { 13,14,15,16}
            };

            Console.WriteLine(arr4.Length);
            Console.WriteLine(arr4.GetLength(0));
            Console.WriteLine(arr4.GetLength(1));

            foreach (int i in arr4) { Console.WriteLine(i); }

따라가기 바쁘다... 헉헉

아래와 같은 3 X 4 배열을 정렬해보자. 

int[,] arr5 = new int[3, 4] { { 6, 9, 10, 2 }, { 4, 8, 1, 11 }, { 15, 0, 7, 12 } };

            Console.WriteLine("정렬 전");
            foreach (int i in arr5) Console.WriteLine(i);

            for (int i = 0; i < arr5.Length - 1; i++)
            {
                for (int j = 0; j < arr5.Length - 1 - i; j++)
                {
                    if (arr5[j / 4, j % 4] > arr5[(j + 1) / 4, (j + 1) % 4])
                    {
                        //스왑
                        int temp = arr5[j / 4, j % 4];                          //temp 변수에 큰 값을 저장
                        arr5[j / 4, j % 4] = arr5[(j + 1) / 4, (j + 1) % 4];    //작은 값을 큰 값이 들어 있는 공간에 대입
                        arr5[(j + 1) / 4, (j + 1) % 4] = temp;                  //작은 값이 있는 공간에 temp의 값(큰 값)을 대입
                    }
                }
            }

            Console.WriteLine("정렬 후");
            foreach (int i in arr5) Console.WriteLine(i);

이쯤부터는 뇌를 열어놓고 들이붓는 느낌이었다. 

제대로 곱씹어 넘어가는 게 아니라 꿀떡꿀떡 넘어가서 뭐가 뭔지 하나도 정리가 안 됐다.

지금 보면 알 것 같지만 나중에 하나도 기억에 안 남을 느낌;;;

이런 게 착착 되는 게 아직도 신기하다... 문명을 만난 원시인의 느낌...

*** 예제 ***
(즐거운 예제의 시간)

5 X 5의 배열을 순차 정렬 형태로 나타내면 아래와 같다. 
            int[,] array = new int[5, 5];
            int idx = 1;

            for (int i = 0; i < array.GetLength(0); i++)
            {
                for (int j = 0; j < array.GetLength(1); j++)
                {
                    array[i, j] = idx++;
                    Console.Write("{0}\t", array[i, j]);
                }

                Console.WriteLine("");
            }

이제부터 게임을 시작하지...

아래와 같이 출력하도록 만들어보자.

요건 처음에는 적잖이 당황했고, 

위의 코드를 따라적기 바빴었기 때문에 처음에는 "이걸 어떻게 풀라는 거야..." 싶었지만...

다시 한번 위의 코드를 한줄 한줄 머리속으로 따라가면서 어떻게 구성된 것인지 알아보려고 했다. 

 

출력되는 배열의 값을 인덱스(idx) 값으로 지정해놓고, 

행렬을 i,j로 지정해서 행에서 하나씩 열이 올라갈 때 인덱스가 하나씩 올라가고, 

열 끝에 다다르면 다음 행으로 넘어가서 다시 하나씩 차오르고 하는 형태였다. 

 

그럼 기본 골격은 똑같으니 25로 시작하고 하나씩 빼기만 하면 된다고 생각했고 그렇게 풀었다. 

다행히 나중에 선생님이 푼 방식과도 동일했다. 

            int[,] arr0 = new int[5, 5];
            int idx = 25;

            for (int a = 0; a < arr0.GetLength(0); a++)
            {
                for (int b = 0; b < arr0.GetLength(1); b++)
                {
                    arr0[a, b] = idx--;
                    Console.Write("{0}\t", arr0[a, b]);
                }
                Console.WriteLine("");
            }

            Console.WriteLine("");
다음 문제... 갑자기 난이도가... 극악으로...

하아... 여기서 정말 오랫동안 막혀 있었다. 

첫번째 시도... 

왠지 원래 구조가 행은 가만히 있고 열이 하나씩 바뀌니까 i와 j를 바꾸면 행이 차면서 저대로 숫자가 들어가지 않을까? 하는 생각을 했었다. .

(무슨 그런 말도 안 되는 바보 같은 생각이냐고 할 수도 있겠지만 그땐 머리 속에서 완벽했다... )

결국 행이 커지는 게 핵심으로 생각을 했다.

이중 반복문 바깥쪽에 열, 안쪽에 행을 배치했다. 

            int[,] arr1 = new int[5, 5];
            int idx = 1;

            for (int i = 0; i < arr1.GetLength(0); i++)
            {
                for (int j = 0; j < arr1.GetLength(1); j++)
                {
                    arr1[j, i] = idx++;
                    Console.Write("{0}\t", arr1[j, i]);
                }
                Console.WriteLine("");
            }

짜잔... ㅠㅠ

완벽히 기존과 동일한 출력이 되었다.....

왜죠? 왜 똑같죠? 분명히 행과 열을 바꿨는데 왜 데이터가 똑같은 거죠? 

이걸 받아들일 수가 없었던 나는 한참을 생각했다. 

 

아... 배열이 되는 것과 출력이 다르구나 하는 걸 한참 뒤에야 깨달았다. 

배열은 내가 상하로 생각한 대로 되었지만 출력은 내가 오른쪽으로 하나씩 뽑게 해놨으니 

배열과 다른 형태로 출력이 되게끔 만들어버린 것이다. 

 

여기서 또 다시 그럼 원래대로 출력이 되게 하려면 어떻게 해야 하지? 

 

멘탈을 다시 가다듬고 두번째 시도... 

이번에는 이래 저래 만져보면서 고민을 좀 다시 해봤다. 

그래 그럼 배열과 동일한 배치로 출력이 되게끔 하자!!! 

            int[,] arr1 = new int[5, 5];
            int idx = 1;

            for (int i = 0; i < arr1.GetLength(0); i++)
            {
                for (int j = 0; j < arr1.GetLength(1); j++)
                {
                    arr1[j, i] = idx++;
                    Console.Write("{0}\t", arr1[i, j]);
                }
                Console.WriteLine("");
            }

하아... 뭐냐 이게...

타이슨의 명언이 생각이 났다. 

"누구나 그럴싸한 계획을 가지고 있다. 쳐 맞기 전까지는"

 

아니 안 되면 아예 안 되든지...

될 거면 되든지... 

분명 나온 부분에는 그럴듯하게 숫자가 배열이 되고 있는데 저기 0은 뭐냐고... 

 

이것 때문에 고민하다가 거의 시간을 다 보냈다. 

강사님이 지나가면서 잘 풀었냐고 해서 이걸 보여 드렸다. 

 

아... 이것 때문에 다들 힘드실 수도 있겠네요.. 하시면서 

배열과 출력을 꼭 같이 하려고 하지 않아도 된다. 따로 해도 된다고 하셨다. 

 

거의 시간은 다 보냈지만 세번째 도전...

            int[,] arr1 = new int[5, 5];
            int idx2 = 1;

            for (int i = 0; i < arr1.GetLength(0); i++)
            {
                for (int j = 0; j < arr1.GetLength(1); j++)
                {
                    arr1[j, i] = idx2++;
                }

            }

            for (int k = 0; k < arr1.GetLength(0); k++)
            {
                for (int l = 0; l < arr1.GetLength(1); l++)
                {
                    Console.Write("{0}\t", arr1[k, l]);
                }
                Console.WriteLine("");
            }
            Console.WriteLine("");

잘 짜여진 건 모르겠고 일단 풀린 것에 만족!

선생님이 푼 것도 거의 동일했다. 

            int[,] array3 = new int[5, 5];
            int idx3 = 1;

            for (int i = 0; i < 5; i++)
            {
                for (int j = 0; j < 5; j++)
                {
                    array3[j, i] = idx3++;
                }
            }
            for (int i = 0; i < 5; i++)
            {
                for (int j = 0; j < 5; j++)
                {
                    Console.Write("{0}\t", array3[i, j]);
                }
                Console.WriteLine("");
            }

Get.Length를 쓰지 않고 그냥 5로 숫자로 바로 넣은 것과

나는 배열과 출력이 따로 라고 생각해서 i, j, k, l의 4개의 변수를 쓴 것과 달리 선생님은 그냥 i와 j로 끝내버렸다. 

 

<다음 두 문제는 숙제!!!>

무슨 난이도가... 1,2,3,4가 아니라 1,2,5,30, 500 이렇게 가냐...

[함수]

함수는 코드들을 묶어놓은 코드 블록이다. 

메소드(Method)라고 하기도 하고, 펑션(Function) 등과 같이 불린다. 

 

이건 바깥에 함수를 정의하고, 안에서 불러오는 형식인데 다소 복잡해서 이미지로 바로 삽입!

오우... 슬슬 복잡의 단계가 확확 올라가는 느낌...

보면 보통 그 동안 코드를 입력하고 테스트 해왔던 static void Main(string[] args) 요 영역이 아니라 

그 밑에 별도로 static void PrintHI[] 를 통해서 별도로 함수를 정의하는 것을 볼 수 있다. 

그 이후 위에서 PrintHI(); 를 넣고 실행하면 아래와 같이 출력이 된다. 

정의해놨던 4줄이 딱 나온다!

삽입되는 형태를 위해서 위에서는 이미지로 넣었고, 

여기서는 코드 블록 형태로 다시 보여주면 매개변수 string으로 구성된 함수를 하나 더 넣어서 보여주겠다.

            PrintHI();          //PrintHI 함수 호출!!! 함수 사용

            PrintString("안녕하십니까");

            string a = "안녕못합니다";

            PrintString(a);
        }

        static void PrintHI()               //반환형식. void 반환하는 값이 없음을 뜻함. 함수 이름은 PrintHI. 매개변수 없음.
        {
            Console.WriteLine("안녕하세요");
            Console.WriteLine("HI");
            Console.WriteLine("Hello");
            Console.WriteLine("반갑습니다");
        }

        static void PrintString(string str)       //반환형식X, 함수이름 PrintSting, 매개변수(string  타입)
        {
            Console.WriteLine(str);
        }

아래에 함수가 추가되었고, 

위에서 다양한 형태로 불러오는 것을 확인할 수 있다.

string 형태의 함수는 직접 수동으로 써 넣을 수도 있고, 변수에 대입하여 출력시킬 수도 있다. 

 

[강의 내용]

https://www.notion.so/2023-07-15-008c6d4a4a0d45698ee26125e7354abf

반응형