# 재귀
def bubble_sort_recur(arr: list, last: int):
if last > 0:
for i in range(0, last):
if arr[i] > arr[i + 1]:
arr[i], arr[i + 1] = arr[i + 1], arr[i]
bubble_sort_recur(arr, last - 1)
# 반복
def bubble_sort_iter(arr: list):
last = len(arr) - 1
while (last > 0):
for i in range(0, last):
if arr[i] > arr[i + 1]:
arr[i], arr[i + 1] = arr[i + 1], arr[i]
last -= 1
arr = [3, 5, 4, 2, 1]
print(arr) # [3, 5, 4, 2, 1]
bubble_sort_recur(arr, len(arr) - 1)
print(arr) # [1, 2, 3, 4, 5]
arr = [3, 5, 4, 2, 1]
print(arr) # [3, 5, 4, 2, 1]
bubble_sort_iter(arr)
print(arr) # [1, 2, 3, 4, 5]
# 재귀
def selection_sort_recur(arr: list, start: int):
if start < len(arr) - 1:
min_index = start
# 이 과정은 리스트를 slice 하여
# 파이썬의 min()메소드를 사용해도 됨
for i in range(start + 1, len(arr)):
if arr[min_index] > arr[i]:
min_index = i
arr[start], arr[min_index] = arr[min_index], arr[start]
selection_sort_recur(arr, start + 1)
# 반복
def selection_sort_iter(arr: list, start: int):
while start < len(arr) - 1:
min_index = start
for i in range(start + 1, len(arr)):
if arr[min_index] > arr[i]:
min_index = i
arr[start], arr[min_index] = arr[min_index], arr[start]
start += 1
arr = [3, 5, 4, 2, 1]
print(arr) # [3, 5, 4, 2, 1]
selection_sort_recur(arr, 0)
print(arr) # [1, 2, 3, 4, 5]
arr = [3, 5, 4, 2, 1]
print(arr) # [3, 5, 4, 2, 1]
selection_sort_iter(arr, 0)
print(arr) # [1, 2, 3, 4, 5]
# 재귀
def insertion_sort_recur(arr: list, cur: int):
if cur < len(arr):
for i in range(cur, -1, -1):
if arr[i] > arr[cur]:
arr[i], arr[cur] = arr[cur], arr[i]
else:
insertion_sort_recur(arr, cur + 1)
else:
return
# 반복
def insertion_sort_iter(arr: list):
for cur in range(1, len(arr)):
for j in range(cur, 0, -1):
if arr[j] > arr[cur]:
arr[cur], arr[j] = arr[j] , arr[cur]
arr = [3, 5, 4, 2, 1]
print(arr) # [3, 5, 4, 2, 1]
insertion_sort_recur(arr, 1)
print(arr) # [1, 2, 3, 4, 5]
arr = [3, 5, 4, 2, 1]
print(arr) # [3, 5, 4, 2, 1]
insertion_sort_iter(arr)
print(arr) # [1, 2, 3, 4, 5]
for i in range(0, mid - part1 + 1):
arr[index + i] = tmp[part1 + i]
def merge_sort(arr: list[int], tmp: list[int], start: int, end: int) :
if start < end:
mid: int = (start + end) // 2
merge_sort(arr, tmp, start, mid) # 계속해서 쪼갬
merge_sort(arr, tmp, mid + 1, end) # 쪼갬
merge(arr, tmp, start, mid, end) # 합병
def merge(arr: list[int], tmp: list[int], start: int, mid: int, end: int):
for i in range(start, end + 1):
tmp[i] = arr[i] # 임시 배열에 복사
part1 = start
part2 = mid + 1
index = start
while part1 <= mid and part2 <= end:
if tmp[part1] <= tmp[part2]:
arr[index] = tmp[part1]
part1 += 1
else:
arr[index] = tmp[part2]
part2 += 1
index += 1
# 뒤쪽 배열에 데이터 남음
for i in range(0, mid - part1 + 1):
arr[index + i] = tmp[part1 + i]
arr = [3, 9, 4, 7, 5, 0, 1, 6, 8, 2]
tmp = [int] * len(arr)
print(arr) # [3, 9, 4, 7, 5, 0, 1, 6, 8, 2]
merge_sort(arr, tmp, 0, len(arr) - 1)
print(arr) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
def quick_sort(arr: list, start: int, end: int):
# start와 end사이에서 파티션을 나누고
# 나눈 파티션의 오른쪽 방 첫 번째 값을 받아옴
part2 = partition(arr, start, end)
# start와 part2가 한개 이상 차이 날 때만.
# 한개 이상 차이가 나지 않는다? = 정렬 할 필요가 없음
if 1 < part2 - start:
# 왼쪽 파티션.
# 끝점이 오른쪽 파티션의 시작점 바로 왼쪽
quick_sort(arr, start, part2 - 1)
# 오른쪽 파티션의 배열방이 한개 이상일 때만 호출
# 오른쪽 파티션의 시작점이 마지막 배열방 보다 작은 경우에만
# 오른쪽 파티션을 정렬
if part2 < end:
quick_sort(arr, part2, end)
def partition(arr: list, start: int, end: int):
pivot = arr[(start + end) // 2] # pivot을 중간에있는값으로
while start <= end:
# 왼쪽부터 차례대로 검사하는데,
# arr[start] 가 pivot보다 작으면 무시하고 넘어감
# 크거나 같으면 멈춤
while arr[start] < pivot: start += 1
# 오른쪽은, arr[end] 값이 pivot보다 크면 무시하고 넘어감
# 작거나 같으면 멈춤
while arr[end] > pivot: end -= 1
# 시작점과 끝점이 만나지는 않았는지 검사
# 안만났으면 swap
if start <= end:
arr[start], arr[end] = arr[end], arr[start]
start += 1
end -= 1
# 이 과정을 start와 end가 만나서 지나칠때까지 반복
return start # 새로 나눌 오른쪽 파티션의 첫번째 배열방 인덱스 반환
arr = [3, 9, 4, 7, 5, 0, 1, 6, 8, 2]
print(arr)
quick_sort(arr, 0, len(arr) - 1)
print(arr)
최대 힙 트리나 최소 힙 트리를 구성해 정렬
내림차순 -> 최대 힙
오름차순 -> 최소 힙
순서는 이렇다.
- n개의 노드에 대한 완전 이진 트리를 구성한다. 이때 루트 노드부터 부모 노드, 왼쪽 자식 오른쪽 자식 노드 순으로 구성한다.
🐋 완전 이진 트리란?
- 마지막 레벨을 제외하고 모든 레벨이 완전히 채워져 있다.
- 마지막 레벨의 모든 노드는 가능한 가장 왼쪽에 있다.
- 최대 힙을 구성한다. (최대 힙이란 부모노드가 자식 노드보다 큰 트리) 단말 노드를 자식노드로 가진 부모노드로부터 구성하며 아래부터 루트까지 올라오며 순차적으로 만들어 갈 수 있다.
- 가장 큰 수(루트에 위치)를 가장 작은 수와 교환한다.
- 2와 3을 반복한다.
이진 트리의 깊이만큼 이루어 지므로 최대 힙을 구성하는데에 의 수행시간이 걸리고
구성된 최대 힙으로 힙 정렬을 수행하는데 n개의 데이터 삭제 및 재구성 시간이 걸리므로 일반적으로 힙 정렬은 의 시간복잡도를 가진다.
Sorting | Average | Worst | Memory | Stable |
---|---|---|---|---|
버블 정렬 | O | |||
선택 정렬 | X | |||
삽입 정렬 | O | |||
합병 정렬 | O | |||
퀵 정렬 | X | |||
힙 정렬 | X |
👀 Stable 하다?
정렬 후에도 같은 키들의 상대적인 순서가 정렬 이전과 동일하게 유지되는 정렬 방법.
문제 | 풀이링크 |
---|---|
백준 11652 - 카드 | 🔗 |
백준 10989 - 수 정렬하기3 | 🔗 |
백준 11728 - 배열 합치기 | 🔗 |
백준 5052 - 전화번호 목록 | 🔗 |
백준 1202 - 보석 도둑 | 🔗 |