• 정렬 알고리즘으로 이진 탐색이 가능해진다.
  • 이진 탐색의 전처리 과정이다.
  • 면접 단골문제

선택 정렬(Selection Sort)

  • 데이터가 무작위로 있을 때 이중에서 가장 작은 데이터를 맨 앞에 있는 데이터와 바꾸고, 그 다음 작은 데이터를 선택해 앞에서 두 번째 데이터와 바꾸는 과정을 반복. 이 방법을 "가장 작은 것을 선택" 한다는 의미에서 선택 정렬 알고리즘이라고 한다.

접은글 ↓↓↓↓↓

더보기

 

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)

선택 정렬의 시간 복잡도

  • 선택 정렬은 기본 정렬 라이브러리를 포함해 뒤에서 다룰 알고리즘과 비교했을 때 매우 비효율적 
  • 다만, 특정한 리스트에서 가장 작은 데이터를 찾는 일이 코딩 테스트에서 잦으므로 선택 정렬 소스코드 형태에 익숙해질 필요가 있다.

삽입정렬

  • "데이터를 하나씩 확인하며, 각 데이터를 적절한 위치에 삽입하면 어떨까"
  • 특정한 데이터를 적절한 위치에 '삽입'한다는 의미에서 삽입 정렬Insertion Sort이라고 부른다. 더불어 삽입 정렬은 특정한 데이터가 적절한 위치에 들어가기 이전에, 그 앞까지의 데이터는 이미 정렬되어 있다고 가정. 정렬되어 있는 데이터 리스트에서 적절한 위치를 찾은 뒤에, 그 위치에 삽입된다는 점이 특징.

접은글 ↓↓↓↓↓

더보기

 

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

for i in range(1, len(array)):
  for j in range(i, 0, -1): # 인덱스 i부터 1까지 감소하며 반복하는 문법
    if array[j] < array[j - 1]: #한 칸씩 왼쪽으로 이동
      array[j], array[j - 1] =  array[j - 1], array[j] 
    else:
      break

print(array)

삽입 정렬의 시간 복잡도

  • 실제로 수행 시간을 테스트해보면 선택 정렬과 흡사하지만 삽입 정렬은 현재 리스트의 데이터가 거의 정렬되어 있는 상태라면 매우 빠르게 동작한다는 점이다.

 

퀵정렬

  • 정렬 알고리즘에서 가장 많이 사용되는 알고리즘
  • '기준 데이터를 설정하고 그 기준보다 큰 데이터와 작은 데이터의 위치를 바꾸면 어떨까'
  • 기준을 설정한 다음 큰 수와 작은 수를 교환한 후 리스트를 반으로 나누는 방식으로 동작
    • 큰 숫자와 작은 숫자를 교환할 때 교환하기 위한 '기준'을 바로 피벗이라고 표현
    • 여러 가지 방식으로 퀵 정렬을 구분하는데 가장 대표적인 분할 방식인 호어 분할 방식을 기준으로 퀵 정렬을 설명
    • 퀵 정렬은 3개의 파트로 나눠서 보는 게 편함

접은글 ↓↓↓↓↓↓↓↓

더보기

 

# 퀵정렬 소스코드
array= [5, 7, 9, 0, 3, 1, 6, 2, 4, 8]

def quicksort(array, start, end):  
  if start >= end: # 원소가 1개인 경우 종료
    return 
  pivot = start # 피벗은 첫 번째 원소
  left = start + 1
  right = end
  while left <= right:
    # 피벗보다 큰 데이터를 찾을 때까지 반복
    while left <= end and array[left] <= array[pivot]:
      left += 1
    # 피벗보다 작은 데이터를 찾을 때까지 반복
    while right > start and array[right] >= array[pivot]:
      right -= 1
    if left > right: # 엇갈렷다면 작은 데이터와 피벗을 교체
      array[right], array[pivot] = array[pivot], array[right]
    else: # 엇갈리지 않았다면 작은 데이터와 큰 데이터를 교체
      array[left], array[right] = array[right], array[left]
  
  # 분할 이후 왼쪽 부분과 오른쪽 부분에서 각각 정렬 수행
  quicksort(array, start, right - 1)
  quicksort(array, right + 1, end)  
  
quicksort(array, 0, len(array) - 1)
print(array)
# 퀵정렬 소스코드
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))

퀵 정렬의 시간 복잡도

  • 앞서 다루었던 두 정렬 알고리즘(선택정렬, 삽입 정렬)에 비해 매우 빠르다.

계수 정렬

  • 특정한 조건이 부합할 때만 사용할 수 있지만 매우 빠른 정렬 알고리즘이다.
  • '데이터의 크기 범위가 제한되어 정수 형태로 표한할 수 있을 때만'사용할 수 있다.
  • EX) 0 이상 100 이하인 성적 데이터를 정렬할 때

접은글↓↓↓↓↓↓

더보기

 

# 계수 정렬 소스코드
# 모든 원소의 값이 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()는 퀵 정렬과 동작 방식이 비슷한 병합 정렬을 기반으로 만들어 졌는데, 병합 정렬은 일반적으로 퀵 정렬보다 느리지만 최악의 경우에도 시간 복잡도 O(NIogN)을 보장한다는 특징이 있음.

접은글 ↓↓↓↓

더보기

sorted()

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

result = sorted(array)
print(result)

sort()

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

array.sort()
print(array)

key 매개변수

array= [( '바나나', 2), ('사과', 5), ('당근', 3)]

def setting(data):
  return data[1]

result = sorted(array, key=setting)
print(result)

정렬 라이브러리의 시간 복잡도

  • 시간복잡도 O(NlogN)을 보장
    1. 정렬 라이브러리로 풀 수 있는 문제: 단순히 정렬 기법을 알고 있는지 물어보는 문제
    2. 정렬 알고리즘의 원리에 대해서 물어보는 문제: 선택 정렬, 삽입 정렬, 퀵 정렬 등의 원리를 알고 있어야 문제를 풀 수 있다.
    3. 더 빠른 정렬이 필요한 문제: 퀵 정렬 기반의 정렬 기법으로는 풀 수 없으며 계수 정렬 등의 다른 정렬 알고리즘을 이용하거나 문제에서 기존에 알려진 알고리즘의 구조적인 개선을 거쳐야 풀 수 있다

+ Recent posts