부트캠프

정렬 알고리즘

noyyo 2023. 9. 4. 23:38

각 정렬에 대해 이해하기 쉽게 정리해보려고 한다.

 

* 정렬해야할 데이터의 크기는 N이다.

* 시간 복잡도는 알고리즘의 시간 복잡도로 코드의 시간 복잡도가 아니다.

(알고리즘에서 N^2번의 비교를 진행하는 것이 코드 상에서도 N^2번의 비교를 진행하는 것이 아니다. for문만 해도 반복할 조건이 되는지 계속 비교를 수행한다.)

* 공간 복잡도는 알고리즘의 공간 복잡도다.

* 안정도는 같은 값을 가진 두 데이터의 순서가 동일하게 유지되는지 그렇지 않을 수 있는지를 의미한다.

 

● 선택정렬

데이터에서 가장 작은 값을 찾아서 앞으로 보내면서 정렬한다.

배열의 앞에서부터 작은 값 순으로 정렬된다.

 

로직 : 

1. 아직 정렬 안된 데이터에서 가장 작은 값을 찾는다.

2. 가장 작은 값을 정렬된 데이터 마지막에 넣는다.

 

코드 : 

void SelectionSort(int[] data, int n)
{
    // 정렬 안된 i번째 데이터에서
    for (int i = 0; i < n - 1; i++)
    {
        // 현재 인덱스를 최소값으로 설정
        int indexMin = i;
        // 마지막 원소까지
        for (int j = i + 1; j < n; j++)
        {
            // 최소값을 찾으면 인덱스를 저장
            if (data[j] < data[indexMin])
            {
                indexMin = j;
            }
        }
        // 최소값과 현재 인덱스의 값을 바꿈
        int temp = data[indexMin];
        data[indexMin] = data[i];
        data[i] = temp;
        // i번째 인덱스까지 정렬됨
    }
}

 

시간 복잡도 : 최선, 평균, 최악 모두 O(n^2)

공간 복잡도 : O(1)

안정 여부 : 불안정

 

●버블정렬

큰 값을 뒤로 보내면서 정렬한다.

배열의 뒤에서부터 큰 값 순으로 정렬된다.

 

로직 :

1. 현재 값과 다음 값을 비교한다.

2. 큰 값을 뒤로 가도록 서로 바꾼다.

3. 다음 인덱스로 이동한다.

4. 1~3번을 반복해서 정렬 안 된 데이터 중 가장 큰 값을 가장 뒤로 보낸다.

5. 정렬된 데이터를 제외하고 1~4번을 반복한다.

 

코드 : 

void BubbleSort(int[] data, int n)
{
    // 정렬 안 된 i번째 값까지
    for (int i = n - 1; i > 0; i--)
    {
        // 0번부터
        for (int j = 0; j < i; j++)
        {
            // 현재 인덱스와 다음 인덱스를 비교
            if (data[j] > data[j + 1])
            {
                // 큰 값을 뒤로 보냄
                int temp = data[j];
                data[j] = data[j + 1];
                data[j + 1] = temp;
            }
        }
        // 가장 큰 값을 뒤로 보내서 i번째부터 마지막 값까지 정렬됨
    }
}

 

시간 복잡도 : 최선 O(n), 평균 및 최악 O(n^2)

공간 복잡도 : O(1)

안정 여부 : 안정

 

최선의 경우는 이미 정렬이 완료되어 있는 경우로 데이터 배열을 1번 비교했을 때 바뀐 내용이 없어 비교를 멈추는 경우이다. (위의 코드에는 구현되어 있지 않다.)

 

삽입정렬

현재 값과 이전의 값들을 비교해서 올바른 위치에 삽입한다.

 

로직 : 

1. 시작 인덱스는 1번이다.

2. 현재 값보다 작은 값이 나올때까지 이전 인덱스들을 탐색한다.

3. 현재 값보다 작은 값이 있다면 그 뒤의 인덱스에 현재 값을 삽입한다.

4. 현재 인덱스를 다음 인덱스로 이동한다.

 

코드 : 

void InsertionSort(int[] data, int n)
{
    // 1번 인덱스부터 마지막까지
    for (int i = 1; i < n; i++)
    {
        // 현재 값을 보관
        int current = data[i];
        int j = i;
        // 현재 값이 이전 값보다 작다면 계속 이전으로 이동
        while (--j >= 0 && current < data[j])
        {
            // 삽입할 공간을 만들기 위해 이전 값을 뒤로 한 칸씩 밀어줌
            // *특정 인덱스에 바로 삽입 가능한 데이터라면 밀어줄 필요 없음.
            data[j + 1] = data[j];
        }
        // 현재 값보다 작은 값이 있다면 그 뒤에 현재 값을 삽입
        data[j + 1] = current;
    }
    // 다음 인덱스로 이동
}

 

시간 복잡도 : 최선 O(n), 평균 및 최악 O(n^2)

공간 복잡도 : O(1)

안정 여부 : 안정

 

최선의 경우는 이미 정렬이 되어있는 경우로 이전 값과 한 번씩만 비교하는 경우이다.

 

●합병정렬

데이터를 한 개의 원소를 가진 배열들로 쪼갠 다음 배열을 2개씩 합치면서 정렬한다.

원본 배열과 같은 크기의 작업용 배열이 필요하다.

 

로직 : 

1. 데이터를 한 개의 원소를 가진 배열이 될 때까지 쪼갠다.

2. 배열을 2개 선택한다.

3. 두 개의 배열에서 원소 하나씩을 비교해서 작은 값을 작업용 배열에 담는다.

4. 작은 값을 가져온 배열에서 인덱스를 한 칸 이동하고 다시 3번을 반복한다. 만약 한 쪽의 배열을 전부 끝냈다면 다른 쪽 배열의 남은 값은 비교 없이 그대로 작업용 배열에 담는다.

5. 2 ~ 4번을 모두 합쳐질 때까지 반복한다.

 

코드 : 

void mergeSort(int[] sourceArray, int low, int high, int[] workingArray)
{
    // 한 개의 원소를 가진 배열이라면 돌아감
    if (low >= high) return;

    // 배열을 두 개로 나눔
    int mid = (low + high) / 2;
    // 왼쪽 오른쪽 배열을 다시 쪼갬
    mergeSort(sourceArray, low, mid, workingArray);
    mergeSort(sourceArray, mid + 1, high, workingArray);

    // 왼쪽과 오른쪽 배열을 합침.
    int left = low, right = mid + 1;
    for (int i = low; i <= high; ++i)
    {
        if (right > high) workingArray[i] = sourceArray[left++];
        else if (left > mid) workingArray[i] = sourceArray[right++];
        else if (sourceArray[left] <= sourceArray[right]) workingArray[i] = sourceArray[left++];
        else workingArray[i] = sourceArray[right++];
    }

    // 작업용 배열에 복사
    for (left = low; left <= high; ++left) sourceArray[left] = workingArray[left];
}

 

시간 복잡도 : 최선, 평균, 최악 모두 O(nlogn)

공간 복잡도 : O(n)

안정 여부 : 안정

 

●퀵 정렬

pivot이라는 임의의 원소를 기준으로 작은 값과 큰 값을 몰아넣고 쪼개는 과정을 반복하면서 정렬한다.

 

코드 : 

public void QuickSort(int[] array, int left, int right)
{
    if (left >= right) { return; }

    int temp;
    int pivot = array[(left + right) / 2];
    int i = left, j = right;
    while (i < j)
    {
        while (array[i] < pivot) { i++; }
        while (pivot < array[j]) { j--; }

        if (i < j)
        {
            if (array[i] == array[j]) { break; }

            temp = array[i];
            array[i] = array[j];
            array[j] = temp;
        }
    }

    QuickSort(array, left, j - 1);
    QuickSort(array, j + 1, right);
}

 

시간 복잡도 : 평균 O(nlogn), 최악 O(n^2)

공간 복잡도 : 평균 O(logn), 최악 : O(nlogn)

안정 여부 : 안정

 

'부트캠프' 카테고리의 다른 글

버튼에 리스너 달기  (0) 2023.09.07
타일맵에서 장애물 투명하게 만들기  (0) 2023.09.06
팀 콘솔RPG 프로젝트 마무리  (0) 2023.09.01
팀 콘솔 RPG3  (0) 2023.08.30
팀 콘솔 RPG2 (스킬 구현)  (0) 2023.08.29