Dia Egg - Shugo Chara

Algorithm/이것이 취업을 위한 코딩테스트다

정렬 간단 정리 (정렬/이론)

별ㅇI 2023. 4. 22. 18:11
728x90
반응형

정렬 간단 정리

정렬이란 데이터를 특정한 기준에 따라서 순서대로 나열하는 것이다. 

이 책 '이것이 취업을 위한 코딩테스트다.'에서는 

  • 선택 정렬
  • 삽입 정렬
  • 퀵 정렬 
  • 계수 정렬

총 4가지를 소개하고 있다. 

 

선택 정렬

이 방법은 가장 원시적인 방법인데, 매번 가장 작은 것을 선택한다는 의미에서 선택정렬이라고 한다.

무작위로 있는 데이터를 오름차순으로 정렬하고자 할 때, 가장 작은 것을 선택하여 앞으로 보내는 알고리즘을 수행하는 알고리즘이다. 

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

for i in range(len(array)):
    min_index = i
    for j in range(i+1, len(array)):
        if array[min_index] > array[j]:
            min_index = j
    array[i], array[min_index] = array[min_index], array[i] #스와프

print(array)

선택정렬은 N(N+1)번의 연산을 하므로 빅오 표기법에 따라

선택정렬의 시간 복잡도는 O(N^2)이다.

삽입 정렬

삽입정렬은 특정한 데이터가 들어가기 이전에, 그 앞까지의 데이터는 이미 정렬되어있다고 가정하고 정렬된 데이터 리스트에서 적절한 위치를 찾은 후에 삽입하는 것이 특징이다. 

삽입정렬은 필요할 때만 위치를 바꾸므로 데이터가 저의 정렬되어있을떄 특히 빠른 알고리즘이다. 

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

for i in range(len(array)):
    for j in range(i, 0, -1): 
        if array[j] <array[j-1]: #한칸씩 왼쪽으로 이동
            array[j], array[j-1] = array[j-1], array[j]
        else: #자신보다 더 작은 수를 만나면 그 위치에서 멈춤
            break

print(array)

삽입정렬의 기본 시간복잡도는 O(N^2)이지만 거의정렬되어있던 경우, 최선의 경우에서는 O(N)을 따른다.

퀵 정렬

퀵정렬은 가장 많이 사용되는데, 피벗을 정하고 그 기준보다 큰데이터와 작은데이터의 위치를 바꾸는 알고리즘이다.

(왼쪽에서는 피벗보다 큰 수를 찾고, 오른쪽에서는 피벗보다 큰 수를 찾아 그 둘의 위치를 변경해줌하고나서는 피벗을 파티션으로 삼아 재귀함수를 통해 똑같은 방법으로 정렬될때까지 시행한다.)

array = [7, 5, 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)이나, 이미 데이터가 정렬되어있는 겨우 즉, 최악의 경우에는 O(N^2)로 매우 느리게 동작하므로 주의 해야한다. 

계수 정렬

게수정렬 알고리즘은 특정한 조건이 부합될 경우만 사용할 수 있는데 바로 아래의 조건이다.

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

이유는 계수 정렬이 모든 범위를 담을 수 있는 리스트(배열)을 선언해야 하기 때문이다. 만약 데이터의 값이 무한란 범위를 받아 가장 큰 데이터와 가장 작은 데이터의 차이가 너무 크다면 쓸모없이 너무 큰 리스트(배열)을 선언해야하기 때문이다.

따라서 위와 같은 조건을 충족 할 대에 한해 계수정렬은 데이터가 많더라도 빠르게 동작한다.

 

먼저 계수정렬을 위해 가장 큰 데이터와 가장 작은 데이터의 범위가 모두 담길 수 있도록 하나의 리스트를 생성한다. 처음에는 리스트의 모든 데이터를 0으로 초기화한다. 그 다음 데이터를 하나씩 확인하며 데이터와 동일한 인덱스의 데이터를 1씩 증가시키면 된다.

#모든 원소의 값이 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=' ') #띄어쓰기를 구분으로 등장한 횟수만큼 출력

계수 정렬의 시간복잡도는 O(N+K)이다. 

 

라이브러리

기본 정렬 라이브러리인 sorted()함수나 sort(), 또는 람다 함수를 사용하는 방법도 있다. 

정렬 라이브러리 같은 경우 최악의 경우에도 O(NlogN)을 보장한다,

728x90
반응형