⌨️ Language/swift

[Swift] νž™(Heap) κ΅¬ν˜„ν•˜κΈ°

hyebin (Helia) 2024. 9. 27. 20:35
λ°˜μ‘ν˜•

Heap은 트리 기반의 자료ꡬ쑰둜, νŠΉμ • μš°μ„ μˆœμœ„μ— 따라 μš”μ†Œλ“€μ„ μ •λ ¬ν•˜λŠ” κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€.

Heap은 크게 두 κ°€μ§€ μœ ν˜•μ΄ μžˆμŠ΅λ‹ˆλ‹€.

μ΅œμ†Œ νž™μ€ μž‘μ€ 값이 λ¨Όμ € λ‚˜μ˜€λ„λ‘ μ •λ ¬ν•˜κ³ , μ΅œλŒ€ νž™μ€ 큰 값이 λ¨Όμ € λ‚˜μ˜€λ„λ‘ μ •λ ¬ν•©λ‹ˆλ‹€.

 

μ œλ„€λ¦­μ„ μ΄μš©ν•΄ Heap ꡬ쑰체λ₯Ό μ •μ˜ν•˜κ³  μ£Όμš” κΈ°λŠ₯을 κ΅¬ν˜„ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

struct Heap<T> {
    private var elements: [T] = []
    private let priorityFunction: (T, T) -> Bool
    
    var isEmpty: Bool {
        return elements.isEmpty
    }
    
    var count: Int {
        return elements.count
    }
    
    var peek: T? {
        return elements.first
    }
    
    init(priorityFunction: @escaping (T, T) -> Bool) {
        self.priorityFunction = priorityFunction
    }
    
    mutating func push(_ element: T) {
        elements.append(element)
        siftUp(from: elements.count - 1)
    }
    
    mutating func pop() -> T? {
        guard !isEmpty else { return nil }
        elements.swapAt(0, count - 1)
        let element = elements.removeLast()
        if !isEmpty {
            siftDown(from: 0)
        }
        return element
    }
    
    private mutating func siftUp(from index: Int) {
        var childIndex = index
        let child = elements[childIndex]
        var parentIndex = self.parentIndex(of: childIndex)
        
        while childIndex > 0 && priorityFunction(child, elements[parentIndex]) {
            elements[childIndex] = elements[parentIndex]
            childIndex = parentIndex
            parentIndex = self.parentIndex(of: childIndex)
        }
        
        elements[childIndex] = child
    }
    
    private mutating func siftDown(from index: Int) {
        let parent = elements[index]
        var parentIndex = index
        
        while true {
            let leftChildIndex = self.leftChildIndex(of: parentIndex)
            let rightChildIndex = leftChildIndex + 1
            
            var candidateIndex = parentIndex
            
            if leftChildIndex < count && priorityFunction(elements[leftChildIndex], elements[candidateIndex]) {
                candidateIndex = leftChildIndex
            }
            
            if rightChildIndex < count && priorityFunction(elements[rightChildIndex], elements[candidateIndex]) {
                candidateIndex = rightChildIndex
            }
            
            if candidateIndex == parentIndex {
                return
            }
            
            elements.swapAt(parentIndex, candidateIndex)
            parentIndex = candidateIndex
        }
        elements[parentIndex] = parent
    }
    
    private func parentIndex(of index: Int) -> Int {
        return (index - 1) / 2
    }
    
    private func leftChildIndex(of index: Int) -> Int {
        return 2 * index + 1
    }
    
    private func rightChildIndex(of index: Int) -> Int {
        return 2 * index + 2
    }
}

 

μœ„ μ½”λ“œμ—μ„œλŠ” Heap의 κΈ°λ³Έ λ™μž‘μ„ κ΅¬ν˜„ν–ˆμŠ΅λ‹ˆλ‹€.

 

  • push(_:): μƒˆλ‘œμš΄ μš”μ†Œλ₯Ό νž™μ— μΆ”κ°€ν•˜κ³  νž™μ˜ 속성을 μœ μ§€ν•©λ‹ˆλ‹€. μ‹œκ°„ λ³΅μž‘λ„λŠ” O(log n)μž…λ‹ˆλ‹€.
  • pop(): νž™μ˜ μ΅œμƒμœ„ μš”μ†Œλ₯Ό μ œκ±°ν•˜κ³  λ°˜ν™˜ν•˜λ©°, 제거 ν›„ νž™μ˜ 속성을 μœ μ§€ν•©λ‹ˆλ‹€. μ‹œκ°„ λ³΅μž‘λ„λŠ” O(log n)μž…λ‹ˆλ‹€.
  • peek: μ΅œμƒμœ„ μš”μ†Œλ₯Ό μ œκ±°ν•˜μ§€ μ•Šκ³  λ°˜ν™˜ν•©λ‹ˆλ‹€. μ‹œκ°„ λ³΅μž‘λ„λŠ” O(1)μž…λ‹ˆλ‹€.
  • siftUp(from:): μƒˆλ‘œμš΄ μš”μ†Œλ₯Ό μ‚½μž… ν›„ μ˜¬λ°”λ₯Έ μœ„μΉ˜λ‘œ μ΄λ™μ‹œν‚΅λ‹ˆλ‹€.
  • siftDown(from:): μ΅œμƒμœ„ μš”μ†Œλ₯Ό μ œκ±°ν•œ ν›„ νž™ 속성을 μœ μ§€ν•˜λ„λ‘ μž¬λ°°μΉ˜ν•©λ‹ˆλ‹€.

κ΅¬ν˜„ν•œ Heap은 λ‹€μŒκ³Ό 같이 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

// μ΅œμ†Œ νž™ ν…ŒμŠ€νŠΈ
var minHeap = Heap<Int> { $0 < $1 }
minHeap.push(3)
minHeap.push(1)
minHeap.push(4)
minHeap.push(1)
minHeap.push(5)

print("Min Heap Test:")
while let element = minHeap.pop() {
    print(element)
}

 

 

좜λ ₯

Min Heap Test:
1
1
3
4
5

 

// μ΅œλŒ€ νž™ ν…ŒμŠ€νŠΈ
var maxHeap = Heap<Int> { $0 > $1 }
maxHeap.push(3)
maxHeap.push(1)
maxHeap.push(4)
maxHeap.push(1)
maxHeap.push(5)

print("\nMax Heap Test:")
while let element = maxHeap.pop() {
    print(element)
}

 

좜λ ₯

Max Heap Test:
5
4
3
1
1

 

 

μ΅œμ†Œ νž™μ€ μ˜€λ¦„μ°¨μˆœμœΌλ‘œ μš”μ†Œλ₯Ό λ°˜ν™˜ν•˜κ³ , μ΅œλŒ€ νž™μ€ λ‚΄λ¦Όμ°¨μˆœμœΌλ‘œ μš”μ†Œλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

이 κ΅¬μ‘°λŠ” μ •λ ¬ μ•Œκ³ λ¦¬μ¦˜μ΄λ‚˜ μš°μ„ μˆœμœ„ 큐 같은 λ‹€μ–‘ν•œ μ‘μš© ν”„λ‘œκ·Έλž¨μ—μ„œ 맀우 μœ μš©ν•˜κ²Œ μ‚¬μš©λ  수 μžˆμŠ΅λ‹ˆλ‹€.

 
λ°˜μ‘ν˜•