- stable ํ๋ค
- ํ๊ท ์๊ฐ๋ณต์ก๋ O(n^2)
func bubbleSort(numStrs: inout [(Int, String)]) -> [(Int, String)] {
for i in 0..<numStrs.count-1 {
for j in 0..<numStrs.count-1-i {
if numStrs[j].0 > numStrs[j+1].0 {
numStrs.swapAt(j, j+1)
}
}
}
return numStrs
}
var arr: [(Int, String)] = [(7, "a"), (5, "a"), (5, "b"), (7, "b"), (3, "c")]
print(bubbleSort(numStrs: &arr))
// [(3, "c"), (5, "a"), (5, "b"), (7, "a"), (7, "b")]
- stable ํ๋ค
- ํ๊ท O(n^2)
func insertionSort(nums: inout [Int]) -> [Int] {
for i in 1..<nums.count {
let tmp: Int = nums[i]
var j: Int = i - 1
while j >= 0 && tmp < nums[j] {
nums[j+1] = nums[j]
j -= 1
}
nums[j+1] = tmp
}
return nums
}
func insertionSort(nums: inout [Int]) -> [Int] {
for i in 1..<nums.count {
let tmp: Int = nums[i]
var j: Int = i - 1
while j >= 0 && tmp < nums[j] {
nums.swapAt(j, j+1)
j -= 1
}
}
return nums
}
var arr: [Int] = [9, 3, 5, 7, 1]
print(insertionSort(nums: &arr))
// [1, 3, 5, 7, 9]
- O(n^2)
- unstable ํ๋ค.
func slectionSort(numStrs: inout [(Int, String)]) -> [(Int, String)] {
for i in 0..<numStrs.count-1 {
var minNum: Int = numStrs[i].0
var minIdx: Int = i
for j in i..<numStrs.count {
if numStrs[j].0 < minNum {
minNum = numStrs[j].0
minIdx = j
}
}
numStrs.swapAt(i, minIdx)
}
return numStrs
}
var arr: [(Int, String)] = [(7, "a"), (5, "a"), (5, "b"), (7, "b"), (3, "c")]
print(slectionSort(numStrs: &arr))
// [(3, "c"), (5, "a"), (5, "b"), (7, "b"), (7, "a")]
- ์๊ฐ๋ณต์ก๋: O(nlogn)
- stable ํ๋ค
func mergeSort(nums: [Int]) -> [Int] {
let count: Int = nums.count
if count == 1 { return nums }
let mid: Int = count / 2
let leftNums: [Int] = Array(nums[0..<mid])
let rightNums: [Int] = Array(nums[mid..<count])
let sortedLeft: [Int] = mergeSort(nums: leftNums)
let sortedRight: [Int] = mergeSort(nums: rightNums)
var sortedNums: [Int] = []
var idxL: Int = 0
var idxR: Int = 0
while idxL < sortedLeft.count || idxR < sortedRight.count {
if idxL == sortedLeft.count {
sortedNums.append(sortedRight[idxR])
idxR += 1
continue
}
if idxR == sortedRight.count {
sortedNums.append(sortedLeft[idxL])
idxL += 1
continue
}
if sortedRight[idxR] <= sortedLeft[idxL] {
sortedNums.append(sortedRight[idxR])
idxR += 1
} else {
sortedNums.append(sortedLeft[idxL])
idxL += 1
}
}
return sortedNums
}
print(mergeSort(nums: [5, 7, 9, 3, 1, 2, 4]))
// [1, 2, 3, 4, 5, 7, 9]
์ ๋ ฌ๋์ง ์์ ๋ฐฐ์ด์์ n๋ฒ์งธ๋ก ํฐ/์์ element๋ฅผ ์ฐพ๋ ๋ฐฉ๋ฒ
- partioning์ ์ฌ์ฉ pivot์ ์ฌ์ฉํด์ pivot๋ณด๋ค ์์์, ํฐ์๋ฅผ ๋๋๋ค.
- ์ ์ฒด ์ ๋ ฌ ํ ๊ฒ์
- O(nlgn)
- heap ์ฌ์ฉ
- O(nlgk)
- Quick Sort
- worst: O(n^2)
- best: O(n)
- average: O(n)
func findKthLargest(_ nums: [Int], _ k: Int) -> Int {
var nums: [Int] = nums
let count = nums.count
if count == 1 { return nums[0] }
let pivot: Int = 0
var left: Int = 1
var right: Int = count - 1
while left <= right {
if nums[left] <= nums[pivot] {
left += 1
continue
}
if nums[right] > nums[pivot] {
right -= 1
continue
}
if nums[left] > nums[pivot] && nums[right] <= nums[pivot] {
nums.swapAt(left, right)
continue
}
}
nums.swapAt(pivot, right)
if right == count - k {
return nums[right]
} else if right > count - k {
return findKthLargest(Array(nums[0..<right]), k - (count - right))
} else {
return findKthLargest(Array(nums[right+1..<count]), k)
}
}
- ์๊ฐ๋ณต์ก๋
- worst: O(n^2)
- average: O(nlgn)
- best: O(nlgn)
- unstable ํ๋ค
- ์๊ฐ๋ณต์ก๋: O(nlgn)
- unstable
struct Heap<T: Comparable> {
private var nodes: [T] = []
let sort: (T, T) -> Bool
init(sort: @escaping (T, T) -> Bool) {
self.sort = sort
}
private func getParentIdx(_ index: Int) -> Int {
return (index - 1) / 2
}
private func getLeftChildIdx(_ index: Int) -> Int {
return index * 2 + 1
}
private func getRighChildtIdx(_ index: Int) -> Int {
return index * 2 + 2
}
var isEmpty: Bool {
return nodes.isEmpty
}
mutating func insert(_ element: T) {
var index: Int = nodes.count
nodes.append(element)
while index > 0 && sort(nodes[index], nodes[getParentIdx(index)]) {
let parentIdx: Int = getParentIdx(index)
nodes.swapAt(index, parentIdx)
index = parentIdx
}
}
mutating func pop() -> T? {
nodes.swapAt(0, nodes.count - 1)
let popped: T? = nodes.popLast()
var index: Int = 0
// ์์์ด ์๋ ๊ฒฝ์ฐ
while getLeftChildIdx(index) <= nodes.count - 1 {
let leftChildIdx: Int = getLeftChildIdx(index)
let rightChildIdx: Int = getRighChildtIdx(index)
// left, right ๋๋ค ์๋ ๊ฒฝ์ฐ
if rightChildIdx < nodes.count {
let child: Int = sort(nodes[leftChildIdx], nodes[rightChildIdx]) ? leftChildIdx : rightChildIdx
if sort(nodes[child], nodes[index]) {
nodes.swapAt(child, index)
index = child
} else {
break
}
} else { // left๋ง ์๋๊ฒฝ์ฐ
if sort(nodes[leftChildIdx], nodes[index]) {
nodes.swapAt(leftChildIdx, index)
index = leftChildIdx
} else {
break
}
}
}
return popped
}
}
var arr: [Int] = [3, 5, 7, 9, 4, 2]
var minHeap: Heap<Int> = Heap<Int>(sort: <)
for e in arr {
minHeap.insert(e)
}
for i in arr.indices {
guard let popped: Int = minHeap.pop() else { break }
arr[i] = popped
}
print(arr)
// [2, 3, 4, 5, 7, 9]
- ์๊ฐ๋ณต์ก๋: O(n+k) (K: ๊ฐ์ฅ์์์ ~ ๊ฐ์ฅํฐ์ ๋ฒ์)
- ๋ฒ์๊ฐ ๋๋ฌด ํฌ๋ฉด ๋นํจ์จ์ ์ด๋ค.
- stable
func countingSort(nums: [Int]) -> [Int] {
let count: Int = nums.count
let minNum: Int = nums.min()!
let maxNum: Int = nums.max()!
let range: Int = maxNum - minNum + 1
var counts: [Int] = Array(repeating: 0, count: range)
for num in nums {
counts[num-minNum] += 1
}
var accessCounts: [Int] = []
var accessCount: Int = 0
for count in counts {
accessCount += count
accessCounts.append(accessCount)
}
accessCounts = accessCounts.map { $0 - 1}
var sorted: [Int] = Array(repeating: 0, count: range)
for i in stride(from: count-1, through: 0, by: -1) {
let num = nums[i]
sorted[accessCounts[num]] = num
accessCounts[num] -= 1
}
return sorted
}
print(countingSort(nums: [3, 4, 0, 1, 2]))
print(countingSort(nums: [3, 0, 5, 1, 0, 5]))
// [0, 1, 2, 3, 4]
// [0, 0, 1, 3, 5, 5]
- counting sort ์ฌ์ฉ
- ์๋ฆฟ์ ๋ณ๋ก ์ ๋ฆฌํ๋ค.
- ์๊ฐ๋ณต์ก๋: O(w*(n+k)) (w: ์ต๋์๋ฆฟ์, k: ์ง๋ฒ์)
import Foundation
func countingSortByDigit(nums: [Int], digit: Int) -> [Int] {
let powed: Int = Int(pow(Double(10), Double(digit)))
var counts: [Int] = Array(repeating: 0, count: 10)
for num in nums {
let countIdx: Int = num / powed % 10
counts[countIdx] += 1
}
var accessCounts: [Int] = []
var accessCount: Int = 0
for count in counts {
accessCount += count
accessCounts.append(accessCount)
}
accessCounts = accessCounts.map { $0 - 1}
var sorted: [Int] = Array(repeating: 0, count: nums.count)
for num in nums.reversed() {
let countIdx: Int = num / powed % 10
let endLoc: Int = accessCounts[countIdx]
sorted[endLoc] = num
accessCounts[countIdx] -= 1
}
return sorted
}
func radixSort(nums: [Int]) -> [Int] {
let maxNum: Int = nums.max()!
let digits = String(maxNum).count
var sorted: [Int] = nums
for digit in 0..<digits {
sorted = countingSortByDigit(nums: sorted, digit: digit)
print(sorted)
}
return sorted
}
print(radixSort(nums: [391, 582, 50, 924, 8, 192]))
// [8, 50, 192, 391, 582, 924]
Bubble | Merge | Selection | Insertion | Quick | Heap | Counting | Radix | |
---|---|---|---|---|---|---|---|---|
Best Time |
n^2 | nlgn | n^2 | n | nlgn | nlgn | n+k (K:๊ฐ์ ๋ฒ์) |
d(n+k) (d:์๋ฆฟ์,k:์ง์) |
Average Time |
n^2 | nlgn | n^2 | n^2 | nlgn | nlgn | n+k | n |
Wrost Time |
n^2 | nlgn | n^2 | n^2 | n^2 | nlgn | n+k | n |
Stability | O | O | X | O | X | X | O | O |