- 최대 힙(Max heap): 값이 더 큰 요소가 높은 우선순위
- 최소 힙(Min heap): 값이 더 작은 요소가 높은 우선순위
struct Heap<Element: Equtable> {
var elements: [Element] = []
let sort: (Element, Element) -> Bool
init(sort: @escaping (Element, Element) -> Bool, elements: [Element] = []) {
self.sort = sort
self.elements = elements
}
}
- 왼쪽 자식: 2i + 1
- 오른쪽 자식: 2i + 2
- floor((i-1)/2)
extension Heap {
var isEmpty: Bool {
elements.isEmpty
}
var count: Int {
elements.count
}
func peek() -> Element? {
elements.first
}
private func leftChildIndex(ofParentAt index: Int) -> Int {
(2 * index) + 1
}
private func rightChildIndex(ofParentAt index: Int) -> Int {
(2 * index) + 2
}
private func parentIndex(ofChildAt index: Int) -> Int {
(index - 1) / 2
}
}
- 루트 노드를 마지막 요소와 교환합니다.
- 두 요소를 교환한 후, 마지막 요소를 제거하고 제거된 값을 반환합니다.
- 힙의 max,min heap 규칙에 의해 다시 힙의 구조를 재조정하며, 이때 sift down을 수행합니다.
extension Heap {
mutating func remove() -> Element? {
guard !isEmpty else {
return nil
}
elements.swapAt(0, count - 1)
defer {
siftDown(from: 0)
}
return elements.removeLast()
}
private mutating func siftDown(from index: Int ) {
var parent = index
while true {
let left = leftChildIndex(ofParentAt: parent)
let right = rightChildIndex(ofParentAt: parent)
var candidate = parent
if left < count && sort(elements[left], elements[candidate]) {
candidate = left
}
if right < count && sort(elements[right], elements[candidate] ) {
candidate = right
}
if candidate == parent {
return
}
elements.swapAt(parent, candidate)
parent = candidate
}
}
}
extension Heap {
mutating func insert(_ element: Element) {
elements.append(element)
siftUp(from: element.count - 1)
}
private mutating func siftUp(from index: Int) {
var child = index
var parent = parentIndex(ofChildAt: child)
whild child > 0 && sort(elements[child], elements[parent]) {
elements.swapAt(child, parent)
child = parent
parent = parentIndex(ofChildAt: child)
}
}
}
mutating func remove(at index: Int) -> Element? {
guard index < elements.count else {
return nil
}
if index == elements.count - 1 {
return elements.removeLast()
} else {
elements.swapAt(index, elements.count - 1)
defer {
siftDown(from: index)
siftUp(from: index)
}
}
return elements.removeLast()
}
func index(of element: Element, startingAt i: Int) -> Int? {
if i >= count {
return nil
}
// 더 높은 우선순위를 검색할 때
if sort(element, elements[i]) {
return nil
}
if let j = index(of: element, startingAt: leftChildIndex(ofParentAt: i)) {
return j
}
if let j = index(of: element, startingAt: rightChildIndex(ofParentAt: i)) {
return j
}
return nil
}
init(sort: @escaping (Element, Element) -> Bool, elements: [Element] = [] ) {
self.sort = sort
self.elements = elements
if !elements.isEmpty {
for i in stride(from: count / 2 - 1, through: 0, by: -1) {
siftDown(from: i)
}
}
}
var heap = Heap(sort: >, elements: [1,12,3,4,1,6,8,7])
var heap2 = Heap(sort: <, elements: [1,12,3,4,1,6,8,7])
print(heap)
print(heap2)
Heap<Int>(elements: [12, 7, 8, 4, 1, 6, 3, 1], sort: (Function))
Heap<Int>(elements: [1, 1, 3, 4, 12, 6, 8, 7], sort: (Function))
Operations | Time Complexity |
---|---|
remove | O(log n) |
insert | O(log n) |
search | O(n) |
peek | O(1) |
제가 학습한 내용을 요약하여 정리한 것입니다. 내용에 오류가 있을 수 있으며, 어떠한 피드백도 감사히 받겠습니다.
감사합니다