티스토리 뷰
기본 정렬 구현하기
오랜만에 알고리즘을 보며 기본 정렬(버블 정렬, 선택 정렬, 삽입 정렬, 퀵 정렬, 병합 정렬)을 구현해봤어요.
알고리즘 풀이를 위해 제가 사용하는 언어인 Python과 iOS 개발을 위해 사용하는 언어인 Swift로 각각 구현했어요.
각 정렬의 시간복잡도나 자세한 정렬 알고리즘을 위한 글이 아니라, 단순히 기본 정렬 알고리즘들을 구현하고 싶은 분들을 위해 코드를 공유해요 :)
제가 구현할 때 했던 생각 정도만 설명으로 추가할게요.
입력되는 배열이 빈 배열인 상황 등은 고려하지 않은 코드예요.
혹시 빈 배열의 입력이 가능한 상황이라면 추가적인 처리가 필요해요 :)
혹시 코드에 미흡한 점이 있거나 더 좋은 코드로 개선 가능한 방향이 있다면 피드백 부탁드려요!
버블 정렬(Bubble Sort)
버블 정렬은 말 그대로 물 위에 떠있는 거품 방울들처럼 바로 옆에 있는 요소들을 비교하며 마지막부터 최댓값을 쌓아 나가는 구조로 오름차순 정렬을 해요.
여기서 포인트는 한 번 반복을 할 때 이미 정렬이 되어있다면 더이상 검색을 진행하지 않기 위해 isAscending이라는 장치를 만들었어요.
Python
def bubble_sort(unsorted: [int]) -> [int]:
for end in range(len(unsorted)-1, 0, -1):
isAscending = True
for start in range(0, end):
if unsorted[start] > unsorted[start+1]:
unsorted[start], unsorted[start+1] = unsorted[start+1], unsorted[start]
isAscending = False
if isAscending: return unsorted
return unsorted
Swift
func bubbleSort(unsorted: [Int]) -> [Int] {
var unsorted = unsorted
for end in stride(from: unsorted.count-1, through: 0, by: -1) {
var isAscending = true
for start in 0...end {
if unsorted[start] < unsorted[start+1] {
unsorted.swapAt(start, start+1)
isAscending = false
}
}
if isAscending { return unsorted }
}
return unsorted
}
선택 정렬(Selection Sort)
선택 정렬은 0번 인덱스부터 뒤로 탐색하며 자신 이후의 배열 중 최솟값이 자신보다 작으면 swap 하는 형태로 구현해요.
버블 정렬에 비해 Swap이 덜 일어난다는게 좋은 것 같아요.
Python
def selection_sort(unsorted: [int]) -> [int]:
for target in range(0, len(unsorted)-1):
min_index = unsorted.index(min(unsorted[target+1:]))
if unsorted[min_index] < unsorted[target]:
unsorted[target], unsorted[min_index] = unsorted[min_index], unsorted[target]
return unsorted
Swift
func selectionSort(unsorted: [Int]) -> [Int] {
var unsorted = unsorted
for start in 0..<unsorted.count-1 {
var partialMinIndex = start
for index in start+1..<unsorted.count {
if unsorted[partialMinIndex] > unsorted[index] {
partialMinIndex = index
}
}
unsorted.swapAt(start, partialMinIndex)
}
return unsorted
}
삽입 정렬(Insertion Sort)
1번 인덱스부터 체크하며 바로 앞부터 시작하여 자신보다 작은 값이 나올 때까지 이동하여 그다음에 위치시키는 정렬이에요.
Python
def insertion_sort(unsorted: [int]) -> [int]:
for target in range(len(unsorted)):
for index in range(target-1, -1, -1):
if unsorted[index] > unsorted[index+1]:
unsorted[index], unsorted[index+1] = unsorted[index+1], unsorted[index]
else:
break
return unsorted
Swift
func insertionSort(unsorted: [Int]) -> [Int] {
var unsorted = unsorted
for end in 1..<unsorted.count {
for start in stride(from: end-1, through: 0, by: -1) {
if unsorted[start] > unsorted[start+1] {
unsorted.swapAt(start+1, start)
} else {
break
}
}
}
return unsorted
}
퀵 정렬(Quick Sort)
피벗(Pivot)이라는 기준점을 만들어 그 피벗보다 작은 값을 피벗 왼쪽에, 큰 값을 오른쪽에 넣으며 정렬시켜요.
단, 아래 구현에서 pivot의 값은 중복되는 경우가 없게 설정했어요.
만약에 중복을 허용하여 구현하고 싶다면 pivot의 개수를 세어 그 개수만큼 넣어주면 될 거라고 생각해요.
그리고 피벗은 0번째 인덱스로 결정했어요.
Python
def quick_sort(unsorted: [int]) -> [int]:
if len(unsorted) < 2:
return unsorted
left, right = [], []
pivot = unsorted[0]
for element in unsorted:
if element < pivot:
left.append(element)
elif element > pivot:
right.append(element)
return quick_sort(left) + [pivot] + quick_sort(right)
Swift
func quickSort(unsorted: [Int]) -> [Int] {
if unsorted.count < 2 { return unsorted }
let pivot = unsorted[0]
let left: [Int] = unsorted.filter { $0 < pivot }
let right: [Int] = unsorted.filter { $0 > pivot }
return quickSort(unsorted: left) + [pivot] + quickSort(unsorted: right)
}
병합 정렬(Merge Sort)
병합 정렬은 나누는 과정과 병합의 과정 두 가지로 구현이 돼요.
나누는 과정은 merge sort라는 메서드로, 병합의 과정은 merge라는 메서드로 구현했어요.
Python
def merge_sort(unsorted: [int]) -> [int]:
if len(unsorted) < 2:
return unsorted
center = len(unsorted) // 2
left = unsorted[:center]
right = unsorted[center:]
return merge(merge_sort(left), merge_sort(right))
def merge(left: [int], right: [int]) -> [int]:
left_index, right_index = 0, 0
merged = []
while left_index < len(left) and right_index < len(right):
if left[left_index] < right[right_index]:
merged.append(left[left_index])
left_index += 1
else:
merged.append(right[right_index])
right_index += 1
merged += left[left_index:] if left_index < len(left) else right[right_index:]
return merged
Swift
func mergeSort(unsorted: [Int]) -> [Int] {
if unsorted.count <= 1 {
return unsorted
}
let centerIndex = unsorted.count / 2
let left = Array(unsorted[0..<centerIndex])
let right = Array(unsorted[centerIndex..<unsorted.count])
return merge(left: mergeSort(unsorted: left), right: mergeSort(unsorted: right))
}
func merge(left: [Int], right: [Int]) -> [Int] {
var result: [Int] = []
var leftIndex = 0
var rightIndex = 0
while leftIndex < left.count && rightIndex < right.count {
if left[leftIndex] < right[rightIndex] {
result.append(left[leftIndex])
leftIndex += 1
} else {
result.append(right[rightIndex])
rightIndex += 1
}
}
if leftIndex == left.count {
result += Array(right[rightIndex..<right.count])
} else {
result += Array(left[leftIndex..<left.count])
}
return result
}
'알고리즘 학습 > 알고리즘 개념' 카테고리의 다른 글
Swift - 에라토스테네스의 체(sieve of Eratosthenes) for 소수 판별 (0) | 2021.08.14 |
---|---|
연결 리스트(Linked List) (0) | 2020.09.15 |
정규표현식 (0) | 2020.09.09 |
최적 부분 구조(Optimal Substructure) (0) | 2020.09.04 |
Quick Sort (퀵소트) (0) | 2020.08.19 |
- Total
- Today
- Yesterday
- 토마토#백준알고리즘#Python
- 리모컨#완전탐색#BOJ#Python
- 순열사이클#BOJ#Python
- 파이썬알고리즘인터뷰#4장
- 병든 나이트#BOJ#탐욕법#Python
- Triangle#Sorting#Codility#Python
- 쿼드트리#BOJ#분할정복#Python
- django#slicing
- PassingCars#Codility#Python
- 배열합치기#분할정복#BOJ#Python
- 종이자르기#분할정복#BOJ#Python
- NumberofDiscIntersections#Codility#Sort#Python
- 나무자르기#BOJ#이분탐색#Python
- 섬의개수#백준알고리즘#Python
- filter#isalnum#lower
- 백준 알고리즘#BackTracking
- N으로 표현#DP#Programmers#Python
- django
- 공유기 설치#BOJ#이분탐색#Python
- Brackets#Stacks and Queues#Codility#Python
- 랜선자르기#이분탐색#BOJ#Python
- 텀 프로젝트#백준알고리즘#Python
- Swift#Tuples#Range
- 날짜 계산#BOJ#완전탐색#Python
- 암호코드#dp#BOJ#Python
- API#lazy#
- 미로 탐색#백준알고리즘#Python
- 터틀비치#리콘#xbox#controller
- 반복수열#백준알고리즘#Python
- Distinct#Codility#Python
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |