Skip to content

Latest commit

ย 

History

History
368 lines (283 loc) ยท 10.7 KB

TIL_2022:10:10_heap.md

File metadata and controls

368 lines (283 loc) ยท 10.7 KB

Today I Learned


2022.10.10 (์›”)


ํž™์ด๋ž€?

ํž™ ํŠธ๋ฆฌ๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๊ฐ’ ์ค‘์—์„œ ๊ฐ€์žฅ ํฌ๊ฑฐ๋‚˜ ์ž‘์€ ๊ฐ’์„ ๋น ๋ฅด๊ฒŒ ์ฐพ๊ธฐ ์œ„ํ•ด ๋งŒ๋“  ์ด์ง„ ํŠธ๋ฆฌ๋กœ, ์งง๊ฒŒ ํž™์ด๋ผ๊ณ  ์ค„์—ฌ์„œ ๋ถ€๋ฅด๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ํž™์€ ์™„์ „ ์ด์ง„ ํŠธ๋ฆฌ์˜ ํ˜•ํƒœ๋ฅผ ๋ ์–ด์•ผ ํ•˜๊ณ , ๋ถ€๋ชจ์˜ ๊ฐ’์€ ํ•ญ์ƒ ์ž์‹๋“ค์˜ ๊ฐ’๋ณด๋‹ค ํฌ๊ฑฐ๋‚˜ ์ž‘์•„์•ผํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ฃจํŠธ ๋…ธ๋“œ๋Š” ์ž์‹ ๋…ธ๋“œ๋ณด๋‹ค ํ•ญ์ƒ ํฌ๊ฑฐ๋‚˜ ์ž‘๊ธฐ ๋•Œ๋ฌธ์— ์ตœ๋Œ“๊ฐ’, ์ตœ์†Ÿ๊ฐ’์€ ํ•ญ์ƒ O(1) ์•ˆ์— ์ฐฟ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์™œ ํ•ญ์ƒ ์™„์ „ ์ด์ง„ํŠธ๋ฆฌ์—ฌ์•ผ ํ•˜๋‚˜์š”?

๋‹จ์ˆœํžˆ ์ตœ๋Œ“๊ฐ’, ์ตœ์†Ÿ๊ฐ’์„ O(1)์•ˆ์— ์ฐพ๊ธฐ ์œ„ํ•ด, "ํ•ญ์ƒ ์™„์ „ ์ด์ง„ ํŠธ๋ฆฌ ํ˜•ํƒœ"์ผ ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์™„์ „ ์ด์ง„ ํŠธ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” ์‚ฝ์ž…ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•  ๋•Œ์˜ ์†๋„๋–„๋ฌธ์ž…๋‹ˆ๋‹ค.

์‹œ๊ฐ„ ๋ณต์žก๋„

๋ฐ์ดํ„ฐ์˜ ์‚ฝ์ž…๊ณผ ์‚ญ์ œ์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋Š” ๋ชจ๋‘ **O(logN)**์ž…๋‹ˆ๋‹ค.

Swift๋กœ ๊ตฌํ˜„ํ•ด๋ณด๊ธฐ

์™„์ „ ์ด์ง„ํŠธ๋ฆฌ์˜ ์ž๋ฃŒ๊ตฌ์กฐ๋Š” ๋ฐฐ์—ด์ด ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ฐฐ์—ด์˜ index๋ฅผ ํŠธ๋ฆฌ๋กœ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ถ€๋ชจ๋…ธ๋“œ์˜ ๋ฒˆํ˜ธ๊ฐ€ 1์ด๋ผ๊ณ  ํ•  ๋•Œ, ์™ผ์ชฝ ์ž์‹๋…ธ๋“œ์™€ ์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ์˜ Index๋Š” 2์™€ 3์œผ๋กœ ์•„๋ž˜์˜ ์‹์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

์™ผ์ชฝ ์ž์‹ ๋…ธ๋“œ index = ๋ถ€๋ชจ๋…ธ๋“œ index * 2
์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ index = ๋ถ€๋ชจ๋…ธ๋“œ index * 2 + 1
๋ถ€๋ชจ ๋…ธ๋“œ index = (์™ผ์ชฝ) ์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ index / 2

๋‹ค๋ฅธ ์‹์œผ๋กœ๋„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (index๊ฐ€ 0๋ถ€ํ„ฐ ์‹œ์ž‘์ผ ๋•Œ)

์™ผ์ชฝ ์ž์‹ ๋…ธ๋“œ index = ๋ถ€๋ชจ๋…ธ๋“œ index * 2 + 1
์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ index = ๋ถ€๋ชจ๋…ธ๋“œ index * 2 + 2
๋ถ€๋ชจ ๋…ธ๋“œ index = ((์™ผ์ชฝ) ์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ index - 1) / 2

๊ทธ๋Ÿผ ๋จผ์ € Heap ๊ตฌ์กฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ฒ ์Šต๋‹ˆ๋‹ค.

struct Heap<T: Comparable> {
    var tree: [T] = []

    init(withData data: T) {
        tree.append(data)
        tree.append(data)
    }
}

Comparable ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋Š” ์ด์œ ๋Š” ๋ถ€๋ชจ์™€ ์ž์‹๋…ธ๋“œ์˜ ๊ฐ’์„ ๋น„๊ตํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ, ์ดˆ๊ธฐํ™”ํ•  ๋•Œ data๋ฅผ ๋‘๋ฒˆ ์‚ฝ์ž…ํ•˜๋Š” ์ด์œ ๋Š” ๋ฐฐ์—ด์˜ 0๋ฒˆ index๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ฌด ์˜๋ฏธ์—†๋Š” ๊ฐ’์„ ์ฑ„์›Œ๋„ฃ๊ธฐ ์œ„ํ•จ์ž…๋‹ˆ๋‹ค.

0๋ถ€ํ„ฐ ์‹œ์ž‘ํ•  ๊ฒฝ์šฐ, ํ•œ ๋ฒˆ๋งŒ ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค.


๋ฐ์ดํ„ฐ์˜ ์‚ฝ์ž…

๋งฅ์Šค ํž™์˜ ๊ฒฝ์šฐ๋งŒ ์ƒ๊ฐํ•ด ๋ณผ ๋•Œ, ์•„๋ž˜์˜ ๊ณผ์ •์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.

  1. ๊ฐ€์žฅ ๋์˜ ์ž๋ฆฌ์— ๋…ธ๋“œ๋ฅผ ์‚ฝ์ž…ํ•œ๋‹ค.
  2. ๊ทธ ๋…ธ๋“œ์™€ ๋ถ€๋ชจ ๋…ธ๋“œ๋ฅผ ์„œ๋กœ ๋น„๊ตํ•œ๋‹ค.
  3. ๋…ธ๋“œ๊ฐ€ ๋ถ€๋ชจ ๋…ธ๋“œ๋ณด๋‹ค ํฌ๋‹ค๋ฉด ์„œ๋กœ ๊ฐ’์„ ๊ตํ™˜ํ•œ๋‹ค.
  4. ๋ถ€๋ชจ ๋…ธ๋“œ๊ฐ€ ๊ฐ€์žฅ ํด ๋•Œ๊นŒ์ง€ 2~3๋ฒˆ ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•œ๋‹ค.
    mutating func insert(_ data: T) {
        // ๋น„์—ˆ๋‹ค๋ฉด ์ดˆ๊ธฐํ™”๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
        if tree.isEmpty {
            tree.append(data)
            tree.append(data)
          	return 
        }

        // ๊ฐ€์žฅ ๋’ค์— ๋…ธ๋“œ๋ฅผ ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค
        tree.append(data)

        var newNodeIndex = tree.count - 1
        var parentNodeIndex = newNodeIndex / 2
        while tree[parentNodeIndex] < tree[newNodeIndex] {
            tree.swapAt(parentNodeIndex, newNodeIndex)
            newNodeIndex = parentNodeIndex
            parentNodeIndex = newNodeIndex / 2

            // ํ˜„์žฌ ๋…ธ๋“œ๊ฐ€ ๋ฃจํŠธ๋…ธ๋“œ์ด๋ฉด ๋”์ด์ƒ ๋น„๊ตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
            if newNodeIndex == 1 { break }
        }
    }

tree์•ˆ์— ์•„๋ฌด ๊ฐ’๋„ ์กด์žฌํ•˜์ง€ ์•Š์„ ๋•Œ insert๊ฐ€ ๋œ๋‹ค๋ฉด ์ดˆ๊ธฐํ™”ํ•  ๋•Œ์ฒ˜๋Ÿผ 0๋ฒˆ ์ธ๋ฑ์Šค์— ์“ธ๋ชจ์—†๋Š” ๊ฐ’์„ ์ฑ„์›Œ์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ’์ด ์žˆ๋‹ค๋ฉด, ๋งˆ์ง€๋ง‰์— ๊ฐ’์„ ์‚ฝ์ž…ํ•˜๊ณ  2~3๋ฒˆ์˜ ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค. ํŠธ๋ฆฌ์˜ ๋ฃจํŠธ ๋…ธ๋“œ์˜ index๋Š” 1์ด๋ฏ€๋กœ ์“ธ๋ชจ์—†๋Š” ๊ฐ’์ด ๋“ค์–ด์žˆ๋Š” index์ธ 0์œผ๋กœ ๊ฐ€์ง€ ์•Š๋„๋ก ํƒˆ์ถœ ์กฐ๊ฑด์„ ๋„ฃ์–ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.


๋ฐ์ดํ„ฐ์˜ ์‚ญ์ œ

๋ฐ์ดํ„ฐ์˜ ์‚ญ์ œ๋Š” ์ตœ๋Œ“๊ฐ’์ธ ๋ฃจํŠธ๋…ธ๋“œ๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

  1. ๋ฃจํ†  ๋…ธ๋“œ๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค.
  2. ๋ฃจํŠธ ๋…ธ๋“œ ์ž๋ฆฌ์— ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ๋ฅผ ์‚ฝ์ž…ํ•œ๋‹ค.
  3. ๋ฃจํŠธ์ž๋ฆฌ์— ์˜ฌ๋ผ๊ฐ„ ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ์™€ ์ž์‹ ๋…ธ๋“œ๋ฅผ ๋น„๊ตํ•œ๋‹ค.
  4. ์•„๋ž˜ ์กฐ๊ฑด์„ ๋”ฐ๋ฅธ๋‹ค.
    1. ๋ถ€๋ชจ๋ณด๋‹ค ๋” ํฐ ์ž์‹์ด ์—†๋‹ค๋ฉด ๊ตํ™˜ํ•˜์ง€ ์•Š๊ณ  ๋๋‚ธ๋‹ค.
    2. ๋ถ€๋ชจ๋ณด๋‹ค ๋” ํฐ ์ž์‹์ด ํ•˜๋‚˜๋งŒ ์žˆ์œผ๋ฉด ๊ทธ ์ž์‹ํ•˜๊ณ  ๊ตํ™˜ํ•œ๋‹ค.
    3. ๋ถ€๋ชจ๋ณด๋‹ค ๋” ํฐ ์ž์‹์ด ๋‘˜์ด๋ผ๋ฉด ์ž์‹๋“ค ์ค‘ ํฐ ๊ฐ’๊ณผ ๊ตํ™˜ํ•œ๋‹ค.
  5. ํ•ด๋‹น ๋…ธ๋“œ๊ฐ€ ๋”์ด์ƒ ๊ตํ™˜๋˜์ง€ ์•Š์„ ๋•Œ๊นŒ์ง€ 3~4๋ฒˆ ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•œ๋‹ค.
    func leftChildIndex(ofParentAt index: Int) -> Int {
        return (2 * index)
    }

    func rightChildIndex(ofParentAt index: Int) -> Int {
        return (2 * index) + 1
    }

    mutating func pop() -> T? {
        guard !tree.isEmpty else { return nil }

        if tree.count == 2 {
            let value = tree[1]
            tree.removeAll()
            return value
        }

        tree.swapAt(1, tree.count - 1)
        let value = tree.removeLast()

        moveDown(from: 1)

        return value
    }

    mutating func moveDown(from index: Int) {
        var parent = index
        while true {
            let left = leftChildIndex(ofParentAt: parent)
            let right = rightChildIndex(ofParentAt: parent)
            var popped = parent

            if left <= count && tree[left] > tree[popped] {
                popped = left
            }
            if right <= count && tree[right] > tree[popped] {
                popped = right
            }
            if popped == parent {
                return
            }
            tree.swapAt(parent, popped)
            parent = popped
        }
    }

tree์˜ index๊ฐ€ 1๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์•ž์— ์กฐ๊ฑด 2๊ฐ€์ง€๊ฐ€ ๋ถ™์Šต๋‹ˆ๋‹ค. ๋น„์—ˆ์„ ๋•Œ nil ๋ฐ˜ํ™˜, 2๊ฐœ์ผ ๋•Œ ๋ชจ๋“  ์‚ญ์ œํ•˜๊ณ  ๋งˆ์ง€๋ง‰๊ฐ’ ๋ฐ˜ํ™˜ํ•˜๊ธฐ.

ํ…Œ์ŠคํŠธํ•ด๋ณด์ž.

var heap = Heap(withData: 10)
heap.insert(50)
heap.insert(20)
heap.insert(100)
print(heap.tree)

heap.pop()
heap.pop()
print(heap.tree)

// [10, 100, 50, 20, 10]
// [10, 20, 10]

์ž˜ ๋‚˜์˜ต๋‹ˆ๋‹ค!

์ตœ๋Œ€ํž™ํŠธ๋ฆฌ๋ฅผ ๊ตฌํ˜„ํ–ˆ์ง€๋งŒ ์ตœ์†Œํž™ํŠธ๋ฆฌ๋ฅผ ๊ตฌํ˜„ํ•˜๋ ค๋ฉด ๋งˆ์ด๋„ˆ์Šค๋กœ ๊ฐ’์„ ๋ณ€ํ™˜ํ•˜์—ฌ ์ง‘์–ด๋„ฃ์„ ์ˆ˜๋„ ์žˆ๊ณ  ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ์˜ ๋ถ€๋“ฑํ˜ธ๋ฅผ ๋ฐ˜๋Œ€๋กœ ๋ฐ”๊พธ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋Œ€๋กœ ๋ฐ”๊ฟ€๋ ค๋ฉด ๋งŽ์ด ๋ฐ”๊พธ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— initializer์—์„œ ๋ฐ›์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

struct Heap<T: Comparable> {
    var tree: [T] = []
    let sort: (T, T) -> Bool
    init(withData data: T, sort: @escaping (T, T) -> Bool) {
        tree.append(data)
        tree.append(data)
        self.sort = sort
    }

  	// ...
}

var heap = Heap(withData: 40, sort: >)

์ง€๊ธˆ๊นŒ์ง€ ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ

struct Heap<T: Comparable> {
    var tree: [T] = []

    init(withData data: T) {
        tree.append(data)
        tree.append(data)
    }

    var isEmpty: Bool {
        return tree.isEmpty
    }

    var count: Int {
        return tree.isEmpty ? 0 : tree.count - 1
    }

    func top() -> T? {
        return tree.isEmpty ? nil : tree[1]
    }

    mutating func insert(_ data: T) {
        // ๋น„์—ˆ๋‹ค๋ฉด ์ดˆ๊ธฐํ™”๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
        if tree.isEmpty {
            tree.append(data)
            tree.append(data)
            return
        }

        // ๊ฐ€์žฅ ๋’ค์— ๋…ธ๋“œ๋ฅผ ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค.
        tree.append(data)

        var newNodeIndex = tree.count - 1
        var parentNodeIndex = newNodeIndex / 2
        while tree[parentNodeIndex] < tree[newNodeIndex] {
            tree.swapAt(parentNodeIndex, newNodeIndex)
            newNodeIndex = parentNodeIndex
            parentNodeIndex = newNodeIndex / 2

            // ํ˜„์žฌ ๋…ธ๋“œ๊ฐ€ ๋ฃจํŠธ๋…ธ๋“œ์ด๋ฉด ๋”์ด์ƒ ๋น„๊ตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
            if newNodeIndex == 1 { break }
        }
    }

    func leftChildIndex(ofParentAt index: Int) -> Int {
        return (2 * index)
    }

    func rightChildIndex(ofParentAt index: Int) -> Int {
        return (2 * index) + 1
    }

    mutating func pop() -> T? {
        guard !tree.isEmpty else { return nil }

        if tree.count == 2 {
            let value = tree[1]
            tree.removeAll()
            return value
        }

        tree.swapAt(1, tree.count - 1)
        let value = tree.removeLast()
        moveDown(from: 1)

        return value
    }

    mutating func moveDown(from index: Int) {
        var parent = index
        while true {
            let left = leftChildIndex(ofParentAt: parent)
            let right = rightChildIndex(ofParentAt: parent)
            var popped = parent

            if left <= count && tree[left] > tree[popped] {
                popped = left
            }
            if right <= count && tree[right] > tree[popped] {
                popped = right
            }
            if popped == parent {
                return
            }
            tree.swapAt(parent, popped)
            parent = popped
        }
    }
}

์ธ๋ฑ์Šค๊ฐ€ 0๋ถ€ํ„ฐ ์‹œ์ž‘ํ•  ๋•Œ์˜ Heap์˜ ๊ตฌํ˜„

struct Heap1<T: Comparable> {
    var tree = [T]()
    let sort: (T, T) -> Bool

    init(sort: @escaping (T, T) -> Bool) {
        self.sort = sort
    }

    var isEmpty: Bool {
        return tree.isEmpty
    }

    var count: Int {
        return tree.count
    }

    func peek() -> T? {
        return tree.first
    }

    func leftChildIndex(ofParentAt index: Int) -> Int {
        return (2 * index) + 1
    }

    func rightChildIndex(ofParentAt index: Int) -> Int {
        return (2 * index) + 2
    }

    func parentIndex(ofChildAt index: Int) -> Int {
        return (index - 1) / 2
    }

    mutating func insert(_ element: T) {
        tree.append(element)
        moveUp(from: tree.count - 1)
    }

    mutating func moveUp(from index: Int) {
        var child = index
        var parent = parentIndex(ofChildAt: child)
        while child > 0 && sort(tree[child], tree[parent]) {
            tree.swapAt(child, parent)
            child = parent
            parent = parentIndex(ofChildAt: child)
        }
    }

    mutating func pop() -> T? {
        guard !tree.isEmpty else { return nil }

        if tree.count == 2 {
            let value = tree[1]
            tree.removeAll()
            return value
        }

        tree.swapAt(1, tree.count - 1)
        let value = tree.removeLast()
        moveDown(from: 1)
        return value
    }
  
    mutating func moveDown(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(tree[left], tree[candidate]) {
                candidate = left
            }
            if right < count && sort(tree[right], tree[candidate]) {
                candidate = right
            }
            if candidate == parent {
                return
            }
            tree.swapAt(parent, candidate)
            parent = candidate
        }
    }
}