SMALL
정렬 알고리즘
| 알고리즘 | 평균 | 최악 | 기법 | 특징 |
| 버블 정렬 | O(n^2) | O(n^2) | 비교, 교환 | 쉬움 |
| 카운팅 정렬 | O(n+k) | O(n+k) | 비교환 | n이 작을때만, k는 정수의 최대값 |
| 선택 정렬 | O(n^2) | O(n^2) | 비교, 교환 | 교환 수가 버블, 삽입 보다 적음 |
| 퀵 정렬 | O(n logn) | O(n^2) | 분할 정복 | 평균적으로 가장 빠름 |
| 삽입 정렬 | O(n^2) | O(n^2) | 비교, 교환 | n의 개수가 작을 때 효과적 |
| 병합 정렬 | O(n logn) | O(n logn) | 분할 정복 | 링크드리스트의 경우 가장 효율적 |
| 힙 정렬 | O(n logn) | O(n logn) | 힙 자료구조 |
버블 정렬
- 첫 번째 원소부터 인접한 원소끼리 자리를 교환하면서 맨 마지막 자리까지 이동
- 한 단계가 끝나면 가장 큰 원소 또는 가장 작은 원소가 마지막 자리로 이동됨

def BubbleSort(list):
n = len(list)
for _ in range(n):
for j in range(n-1):
if list[j] > list[j+1]:
list[j], list[j+1] = list[j+1], list[j]
return list
카운팅 정렬
- 정수나 정수로 표현할 수 있는 자료에 대해서만 적용 가능
- 각 항목의 발생 회수를 기록하기 위해, 정수 항목으로 인덱스되는 카운트들의 리스트를 사용하기 때문
- 카운트들을 위한 충분한 공간을 할당하려면 집합 내의 가장 큰 정수 k를 알아야 함
- n이 커질수록 추가적인 메모리 낭비가 커지므로, n이 작을때만 사용이 가능

def CountingSort(list, k):
n = len(list)
count_list = [0]*(k+1) # 최댓값 k 크기의 카운팅 리스트
sorted_list = [-1]*n # 정렬된 결과 리스트
# 각 요소가 등장하는 횟수 카운팅
for elem in list:
count_list[elem] += 1 # 요소의 값을 카운팅 리스트의 인덱스로 사용하여 횟수 증가
# 카운팅 리스트 값을 누적 합으로 바꿈
for i in range(1, k+1):
count_list[i] += count_list[i-1]
# 정렬된 리스트 채움
for i in range(1, n+1):
id = count_list[list[-i]] # 요소의 카운팅 값
sorted_list[id-1] = list[-i]
count_list[list[-i]] -= 1 # 카운팅 값 -1
return sorted_list
⭐ 이렇게 풀 수도 있어요! 메모리를 더 적게!
2021.08.11 - [Coding Test/백준 (BOJ)] - 백준 10989 - 실버5
백준 10989 - 실버5
10989번: 수 정렬하기 3 (acmicpc.net) 10989번: 수 정렬하기 3 첫째 줄에 수의 개수 N(1 ≤ N ≤ 10,000,000)이 주어진다. 둘째 줄부터 N개의 줄에는 숫자가 주어진다. 이 수는 10,000보다 작거나 같은 자연수..
k0k1.tistory.com
선택 정렬
- 가장 작은 값의 원소부터 차례대로 선택하여 위치를 교환하는 방식
- 즉, 각각의 반복마다 최소값을 찾아 맨 앞의 값과 교환

def SelectionSort(list):
n = len(list)
for i in range(n):
min = list[i]
min_id = None
for j in range(i+1, n): # 뒤에 리스트 중에서 최소값 찾음
if list[j] < min:
min = list[j]
min_id = j
if min_id: # 최소값 발견된 경우
list[i], list[min_id] = list[min_id], list[i]
return list
퀵 정렬
- 리스트를 두 개로 분할하고, 각각의 정렬
- 기준 아이템을 중심으로 작은 것은 왼쪽, 큰 것은 오른쪽에 위치 시킴

def quick_sort(A, l, r): # 리스트, 시작 인덱스, 끝 인덱스
if l < r:
s = HoarePartition(A, l, r)
quick_sort(A, l, s-1)
quick_sort(A, s+1, r)
def HoarePartition(A, l, r): # Hoare
pivot = A[l] # 피봇 : 맨앞
L = l+1
R = r
while L <= R:
while L <= R and A[L] <= pivot: # pivot 보다 큰 값이 나올 때까지 이동
L += 1
while L <= R and A[R] >= pivot: # pivot 보다 작은 값이 나올 때까지 이동
R -= 1
if L <= R:
A[L], A[R] = A[R], A[L] # L과 R의 요소 교환
A[l], A[R] = A[R], A[l] # 마지막에는 pivot과 R을 교환
return R
⭐ 참고!
파이썬에서 리스트는 가변객체로(mutable object), 함수의 argument로 전달할 때 Call by Reference가 된다.
따라서, 리스트를 리턴하지 않아도 원래 객체가 변경된다.
삽입 정렬
- 리스트의 두 번째 요소부터 시작
- 앞부분의 리스트는 정렬된 집합으로, 현재 요소가 정렬된 집합에 어느 위치에 들어갈지 결정함
- 교환이 안일어나면 베스트는 O(n)

def InsertionSort(list):
n = len(list)
for end in range(1, n):
for i in range(end, 0, -1):
if list[i-1] > list[i]:
list[i-1], list[i] = list[i], list[i-1]
병합 정렬
- 자료를 최소 단위의 문제까지 분할하고, 차례대로 정렬
- Top-Down 방식

import collections
def merge_sort(m):
if len(m) <= 1: # 사이즈가 0이거나 1인 경우, 바로 리턴
return m
# DIVIDE
mid = len(m) // 2
left = m[:mid]
right = m[mid:]
# Recursion
left = merge_sort(left)
right = merge_sort(right)
# CONQUER
return merge(left, right)
def merge(left, right):
result = [] # 두 리스트를 병합하여 result를 채움
left = collections.deque(left) # 시간 효율성을 위해 deque로 변환
right = collections.deque(right)
while len(left)>0 and len(right)>0:
# 두 리스트의 첫 원소들을 비교하여 작은 것부터 result에 추가
if left[0] <= right[0]:
result.append(left.popleft())
else:
result.append(right.popleft())
# 왼쪽 리스트에 원소 남아있는 경우
if len(left) > 0:
result += left
# 오른쪽 리스트에 원소 남아있는 경우
if len(right) > 0:
result += right
return result
힙 정렬
- 최대 힙 트리(내림차순)나 최소 힙 트리(오름차순)를 구성해 정렬하는 방법
- 정렬할 요소들로 완전 이진 트리 형태인 최대/최소 힙을 만든다.
- 한 번에 하나씩 요소를 힙에서 꺼내서 배열의 뒤부터 저장한다.

정렬 알고리즘의 비교
- 구현이 간단하지만 비효율적인 방법 : 버블, 카운팅, 선택, 삽입
- 복잡하지만 효율적인 방법 : 퀵, 병합, 힙
정렬에서 Stable의 개념
stable 정렬이란 "정렬되지 않은 상태에서 같은 값을 가진 원소의 순서가 정렬 후에도 유지되는 알고리즘"를 의미한다.
- stable 정렬 : 버블, 카운팅, 삽입, 병합
- unstable 정렬 : 선택, 퀵, 힙
정렬에서 In-Place의 개념
In-Plcae 정렬이란 "원소들의 개수 N에 비해서 충분히 무시할 만한 저장 공간만을 더 사용하는 알고리즘"을 의미한다.
정렬을 위한 추가적인 메모리 공간이 거의 안 드는 정렬 알고리즘이라고 생각하면 된다.
- In-Place : 버블, 선택, 퀵, 삽입, 힙
- Not In-Place : 카운팅, 병합
'CS study > Algorithm' 카테고리의 다른 글
| 6. 그래프 탐색 - DFS,BFS (0) | 2021.09.01 |
|---|---|
| 5. 그리디 알고리즘 (0) | 2021.08.30 |
| 4. 백트래킹 (0) | 2021.08.27 |
| 3. 완전검색, 분할정복 (0) | 2021.08.26 |
| 2. 부분집합, 순열, 조합 (0) | 2021.08.12 |
댓글