Algorithm/concept

Coding Test(정렬 알고리즘)

땅지원 2024. 1. 7. 18:11

선택정렬

- 가장 작은 데이터를 선택해 맨 앞에 있는 데이터와 바꾼다.

- 한번씩 순회를 하고 가장 큰 수를 찾은다음 바꿈

- 시간 복잡도 : O(N*2)

- 공간 복잡도 : O(N)

int[] arr = {7, 5, 2, 4, 6, 1, 3, 9, 8};

for (int i = 0; i < arr.length; i++) {
    int min = i;
    for (int j = i+1; j < arr.length; j++) {
        if (arr[min] > arr[j]) {
            min = j;
        }
    }

    int temp = arr[i];
    arr[i] = arr[min];
    arr[min] = temp;
}

삽입정렬

처리되지 않은 데이터를 하나씩 골라 적절한 위치에 삽입한다.

- 현재위치에서 아래쪽을 순회하며 크기가 작을수록 계속 swap을 해주는 정렬방식

- 시간 복잡도 : O(N*2)

- 공간 복잡도 : O(N)

- 하지만 거의 정렬되어있는 상태라면 매우빠르게 동작 : O(N)

int[] arr = {7, 5, 2, 4, 6, 1, 3, 9, 8};

for (int i = 1; i < arr.length; i++) {
    for (int j = i; j > 0; j--) {
        if (arr[j] < arr[j - 1]) {
            int temp = arr[j];
            arr[j] = arr[j - 1];
            arr[j - 1] = temp;
        } else {
            break;
        } 
    }
}

버블정렬

- 두개씩 짝을 지어서 정렬을 하나씩 실행함

- 시간 복잡도 : O(N*2)

- 공간 복잡도 : O(N)

int[] arr = {7, 5, 2, 4, 6, 1, 3, 9, 8};

for (int i = 1; i < arr.length; i++) {
    for (int j = 0; j < arr.length-1; j++) {
        if (arr[i] < arr[j]) {
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
}

 

퀵정렬

기준 데이터를 설정하고 기준보다 큰 데이터와 작은 데이터의 위치를 바꾸는 방법

- 가장 많이 사용되는 정렬 알고리즘

- 가장 기본적인 퀵 정렬은 첫 번째 데이터를 기준 데이터로 설정

- 시간 복잡도 : O(NlogN)

- 공간 복잡도 : O(N)

- 하지만 최악의 경우 O(N^2)

array = [5, 7, 9, 0, 3, 1, 6, 2, 4, 8]

def quick_sort(array):
    # 리스트가 하나 이하의 원소만을 담고 있다면 종료
    if len(array) <= 1:
        return array

    pivot = array[0] # 피벗은 첫 번째 원소
    tail = array[1:] # 피벗을 제외한 리스트

    left_side = [x for x in tail if x <= pivot] # 분할된 왼쪽 부분
    right_side = [x for x in tail if x > pivot] # 분할된 오른쪽 부분

    # 분할 이후 왼쪽 부분과 오른쪽 부분에서 각각 정렬을 수행하고, 전체 리스트를 반환
    return quick_sort(left_side) + [pivot] + quick_sort(right_side)

print(quick_sort(array))

병합정렬

- 정렬할 리스트를 반으로 쪼개나가며 좌측과 우측 리스트를 계속해서 분할해 나간 후 각 리스트내에서 정렬 후 병합한다

- 시간복잡도 O(nlogn)을 보장

계수정렬

- 특정 조건이 부합할 때만 사용할 수 있지만 매우 빠르게 동작하는 알고리즘

- 데이터의 크기 범위가 제한되어 정수 형태로 표현할 수 있을 때 사용 가능

- 데이터의 개수가 N, 데이터(양수) 중 최댓값이 K일 때 최악의 경우에도 O(N+K)

- 공간복잡도 :  O(N+K)

- 동일한 값을 가지는 데이터가 여러 개 등장할 때 효과적으로 사용가능

# 모든 원소의 값이 0보다 크거나 같다고 가정
array = [7, 5, 9, 0, 3, 1, 6, 2, 9, 1, 4, 8, 0, 5, 2]
# 모든 범위를 포함하는 리스트 선언 (모든 값은 0으로 초기화)
count = [0] * (max(array) + 1)

for i in range(len(array)):
    count[array[i]] += 1 # 각 데이터에 해당하는 인덱스의 값 증가

for i in range(len(count)): # 리스트에 기록된 정렬 정보 확인
    for j in range(count[i]):
        print(i, end=' ') # 띄어쓰기를 구분으로 등장한 횟수만큼 인덱스 출력

- 0,999999만 존재하는 경우를 생각해보면 1,000,000개의 공간을 만들어야하기 때문에 매우 비효율적

 

퀵정렬

- 가장 많이 쓰는 정렬알고리즘

- pivot을 선정하여 pivot을 기준으로 좌측과 우측으로 pivot보다 작은값은 왼쪽 pivot보다 큰값은 오른쪽으로 재배치를 하고 계속하여 분할하여 정렬하는 알고리즘

- 일반적으로 O(nlogn), 최악O(N^2)