기본 정렬에 대해서 정리해 놓는다.
그냥 나 알아보기 쉽게, 직관적으로만 설명한다.
시간 복잡도 O(n^2) 정렬
선택 정렬
뒤에 가장 큰, 또는 가장 작은 값을 현재 인덱스 뒤부터 찾아, 앞의 인덱스부터 하나씩 채워나가는 정렬.
# selection sort
a = [3,1,2,5,4,6,7]
size = len(a)
for i in range(size):
for j in range(i+1, size):
if a[j] < a[i]:
a[i], a[j] = a[j], a[i]
print(a)
버블 정렬
뒤에 가장 큰, 또는 가장 작은 값을 뒤로 밀어밀어 보내, 마지막 인덱스부터 하나씩 채워나가는 정렬
# bubble sort
a = [3,1,2,5,4,6,7]
size = len(a)
for i in range(size):
for j in range(i+1, size):
if a[j] < a[j-1]:
a[j], a[j-1] = a[j-1], a[j]
print(a)
삽입 정렬
차근차근 정렬을 쌓아오며, 필요한 경우 모두 일괄적으로 땡기며 정렬
# insertion sort
a = [3,1,2,5,4,6,7]
size = len(a)
for i in range(1, size):
tmp, j = a[i], i-1
while j >= 0 and a[j] > tmp:
a[j+1] = a[j]
j -= 1
a[j+1] = tmp
print(a)
- 정렬이 다 된건 아니지만, 그래도 좀 정렬이 되어있으면, 다른 정렬들보다 효율적
- 구현 상, Best 시간 복잡도가 O(n) 이다. (모두 정렬되어있는 경우)
시간 복잡도 O(n log n) 정렬
머지 정렬
분할 정복으로, 데이터를 반으로 계속 쪼개나가다가 다시 하나씩 정렬하며 정복하는 정렬
# merge sort
def merge_sort(a):
size = len(a)
if size >= 2:
# 반으로 쪼갠다. 왼쪽, 오른쪽 파트로.
l, r = merge_sort(a[:size//2]), merge_sort(a[size//2:])
ret = []
i, j = 0, 0
# 쪼개어진 왼쪽 파트, 오른쪽 파트를 비교하며, 정렬된 새로운 리스트를 만든다.
while i < len(l) and j < len(r):
if l[i] <= r[j]:
ret.append(l[i])
i += 1
else:
ret.append(r[j])
j += 1
# 왼쪽, 오른쪽 파트에 남겨진 아이템들을 마저 새로운 리스트에 넣어준다.
while i < len(l):
ret.append(l[i])
i += 1
while j < len(r):
ret.append(r[j])
j += 1
# 정렬된 새로운 리스트 반환
return ret
else:
return a
a = [3,1,2,5,4,6,7]
print(merge_sort(a))
퀵 정렬
머지 정렬은 가운데를 딱 나누는 반면, 퀵 정렬은 그냥 임의의 한 값 (pivot)을 기준으로 반반 나눈다.
# quick sort
def quick_sort(a):
size = len(a)
if size >= 2:
# 임의의 값, 여기서는 0번째 값을 pivot으로 둔다.
pivot = a[0]
# pivot 을 기준으로 반반 나눈다.
lesser = [e for e in a[1:] if e <= pivot]
greater = [e for e in a[1:] if e > pivot]
# 반반 한거 정렬한 뒤 합친 리스트 반환
return quick_sort(lesser) + [pivot] + quick_sort(greater)
else:
return a
a = [3,1,2,5,4,6,7]
- 최악의 경우 O(n^2) 까지 뜨지만, 평균적으로 가장 빠르다고 한다. 그래서 퀵.
- pivot 값을 무엇을 잡느냐에 따라 시간 최적화가 가능하다.
힙 정렬
힙이라는 자료구조를 이용해 정렬하는 정렬.
우선순위를 고려하는 자료구조인 힙을 먼저 알아야한다. 그리고 힙을;;; 짜야한다.
# heap sort
class min_heap:
def __init__(self, arr):
self.a = []
self.heap_size = 0
for e in arr:
self.insert(e)
def insert(self, e):
self.a.append(e)
self.heap_size += 1
self.heapify(0)
def delete(self):
ret = self.a[0]
self.a[0] = self.a[-1]
self.a.pop()
self.heap_size -= 1
self.heapify(0)
return ret
def heapify(self, index):
left_index, right_index = 2 * index + 1, 2 * index + 2
smallest = index
if left_index < self.heap_size and self.a[left_index] < self.a[smallest]:
smallest = left_index
if right_index < self.heap_size and self.a[right_index] < self.a[smallest]:
smallest = right_index
if smallest != index:
self.a[index], self.a[smallest] = self.a[smallest], self.a[index]
self.heapify(smallest)
def sort(self):
from copy import deepcopy
tmp = deepcopy(self.a)
ret = []
while self.a:
ret.append(self.delete())
self.a = tmp
return ret
a = [3,1,2,5,4,6,7]
print(min_heap(a).sort())
참고한 링크
Heejeong Kwon님 블로그. 삽입 정렬이란
Ratsgo's blog. 퀵 정렬
열코의 프로그래밍 일기. 정렬 알고리즘 종류
'취업과 기본기 튼튼 > 빽 투더 기본기' 카테고리의 다른 글
빽 투더 기본기 [알고&자구 3편]. 균형 트리 (0) | 2019.04.17 |
---|---|
빽 투더 기본기 [알고&자구 2편]. 자료구조 기초 (0) | 2019.04.17 |
재귀적으로 문제 해결하기 (1) (0) | 2018.08.20 |
큐 구현하기 (0) | 2018.08.17 |
연결리스트 구현하기 (0) | 2018.08.17 |