📚 /algorithm

1. 선형 시간 선택 알고리즘 (Linear-Time Selection)


선형 시간 선택 알고리즘은 정렬되지 않은 데이터에서 원하는 순서의 요소(예: k번째로 작은 요소)를 선형 시간 내에 찾는 알고리즘이다. 일반적으로 정렬 알고리즘을 사용하여 데이터를 정렬한 후 원하는 요소를 찾을 수 있지만, 이는 보통 $O(n log n)$ 의 시간 복잡도를 갖는다. 그러나 선형 시간 선택 알고리즘은 정렬되지 않은 상태에서 $O(n)$ 의 시간 복잡도로 원하는 요소를 찾을 수 있다.

1-1. 아이디어 분석

이 알고리즘은 퀵 정렬(Quick Sort)의 분할 방식을 활용한다. 주어진 배열에서 임의의 피벗(pivot)을 선택하고, 이 피벗을 기준으로 배열을 분할한다. 피벗보다 작은 요소들은 왼쪽 부분 배열에, 큰 요소들은 오른쪽 부분 배열에 위치시킨다. 이때 피벗의 정확한 위치(인덱스)를 알 수 있으며, 이를 통해 원하는 k번째 요소가 피벗의 위치와 비교하여 어느 부분 배열에 존재하는지 판단할 수 있다.



2. 구현 분석


int select(int *arr, int left, int right, int k) {
    if (k >= 0 && k < right - left + 1) {
        int n = right - left + 1;
        int pivot = arr[left + rand() % n];

        // 분할 과정
        int pivot_idx = partition(arr, left, right, pivot);

        // 피벗의 위치와 k 비교
        if (pivot_idx - left == k)
            return arr[pivot_idx];
        else if (pivot_idx - left > k)
            return select(arr, left, pivot_idx - 1, k);
        else
            return select(arr, pivot_idx + 1, right, k - (pivot_idx - left + 1));
    }
    return INT_MAX; // 오류 처리
}

2-1. 함수 select

int select(int *arr, int left, int right, int k)

이 함수는 배열 arr에서 left부터 right까지의 범위에서 k번째로 작은 요소를 찾는 함수이다.


2-2. 함수 partition

partition 함수는 퀵 정렬에서 사용하는 분할 함수로, 피벗을 기준으로 배열을 재배열한다. 코드 구현은 다음과 같다.

int partition(int *arr, int left, int right, int pivot) {
    while (left <= right) {
        while (arr[left] < pivot)
            left++;
        while (arr[right] > pivot)
            right--;
        if (left <= right) {
            swap(arr[left], arr[right]);
            left++;
            right--;
        }
    }
    return left - 1;
}


3. 정확성 분석


선형 시간 선택 알고리즘은 퀵 정렬의 분할 방식을 활용하여 원하는 순서의 요소를 찾는다. 이제 수학적 귀납법을 통해 알고리즘의 정확성을 증명해보자.


3-1. 명제 설정

명제 P(n): 배열 크기가 n일 때, select 함수는 k번째로 작은 요소를 정확히 찾아낸다.


3-2. 귀납적 증명의 구성 요소

  1. 기저 사례(Base Case): n = 1일 때, 명제가 참임을 보인다.
  2. 귀납 가정(Inductive Hypothesis): 배열 크기가 n보다 작은 모든 경우에 대해 명제가 참이라고 가정한다.
  3. 귀납 단계(Inductive Step): 배열 크기가 n인 경우에도 명제가 참임을 보인다.
  4. 종료성(Termination): 알고리즘이 유한한 단계 내에 종료함을 보인다.

3-3. 귀납적 증명

기저 사례


귀납 가정


귀납 단계


종료성


결론



4. 효율성 분석


선형 시간 선택 알고리즘의 시간 복잡도를 분석해보자.


4-1. 평균 시간 복잡도


4-2. 최악 시간 복잡도


4-3. 최선 시간 복잡도


4-4. 개선 방안



5. 결론


선형 시간 선택 알고리즘은 퀵 정렬의 분할 방식을 활용하여 정렬되지 않은 배열에서 원하는 순서의 요소를 효율적으로 찾을 수 있다. 평균적으로 O(n)의 시간 복잡도를 가지며, 추가적인 메모리 공간을 필요로 하지 않는다. 무작위 피벗 선택을 통해 최악의 경우를 피할 수 있으며, 큰 데이터 집합에서 효율적으로 동작한다. 그러나 최악의 경우 O(n^2)의 시간 복잡도를 가질 수 있으므로, 이러한 상황을 방지하기 위한 추가적인 전략이 필요할 수 있다.