๊ธ€ ์ž‘์„ฑ์ž: ๊ฐœ๋ฐœํ•˜๋Š” ํ›ˆ์ด

์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ (BST)

์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ๋Š” ์ด์ง„ ํŠธ๋ฆฌ์— ๋ช‡๊ฐ€์ง€ ์กฐ๊ฑด์ด ๋” ์ถ”๊ฐ€๋œ ํŠธ๋ฆฌ์ž…๋‹ˆ๋‹ค. ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ๋Š” ๋‹ค์Œ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

 

1) ์–ด๋–ค ๋ฃจํŠธ๋…ธ๋“œ(์„œ๋ธŒํŠธ๋ฆฌ์˜ ๋ฃจํŠธ ํฌํ•จ)์˜ ์™ผ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ์˜ ๋…ธ๋“œ๋“ค์ด ๊ฐ€์ง„ ๊ฐ’์€ ๋ฃจํŠธ ๋…ธ๋“œ๊ฐ€ ๊ฐ€์ง„ ๊ฐ’๋ณด๋‹ค ์ž‘์•„์•ผํ•ฉ๋‹ˆ๋‹ค.

2) ์–ด๋–ค ๋ฃจํŠธ๋…ธ๋“œ์˜ ์˜ค๋ฅธ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ์˜ ๋…ธ๋“œ๋“ค์ด ๊ฐ€์ง„ ๊ฐ’์€ ๋ฃจํŠธ ๋…ธ๋“œ๊ฐ€ ๊ฐ€์ง„ ๊ฐ’๋ณด๋‹ค ์ปค์•ผํ•ฉ๋‹ˆ๋‹ค.

3) ๋…ธ๋“œ์˜ ๊ฐ’์œผ๋กœ ํŠธ๋ฆฌ ์—ฐ์‚ฐ์ด ์ด๋ฃจ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ์ค‘๋ณต๋œ ๋…ธ๋“œ ๊ฐ’์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. 

์˜ˆ๋ฅผ ๋“ค์–ด, ์ด๋Ÿฐ ํŠธ๋ฆฌ๋Š” ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ๊ฐ€ ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ฃจํŠธ ๋…ธ๋“œ์ธ 1๋ณด๋‹ค ํฐ ๊ฐ’์ธ 2๊ฐ€ ์™ผ์ชฝ ์ž์‹ ๋…ธ๋“œ์— ์œ„์น˜ํ•ด์žˆ๊ณ  ์™ผ์ชฝ ์ž์‹ ๋…ธ๋“œ์ธ 4, 6๋„ ๋ชจ๋‘ ์ž์‹ ์˜ ๋ถ€๋ชจ ๋…ธ๋“œ์˜ ๊ฐ’๋ณด๋‹ค ํฌ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค

๋ฐ˜๋ฉด์— ์ด๋Ÿฐ ํŠธ๋ฆฌ๋Š” ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฃจํŠธ๋…ธ๋“œ์ธ 4์˜ ์™ผ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ์˜ ๋ชจ๋“  ๋…ธ๋“œ๋“ค์€ 4๋ณด๋‹ค ์ž‘๊ณ , ์˜ค๋ฅธ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ์˜ ๋ชจ๋“  ๋…ธ๋“œ๋“ค์€ 4๋ณด๋‹ค ํฝ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋…ธ๋“œ 2์™€ 6 ์—ญ์‹œ๋„ ์™ผ์ชฝ์—๋Š” ์ž์‹ ๋ณด๋‹ค ์ž‘์€ ๊ฐ’, ์˜ค๋ฅธ์ชฝ์—๋Š” ์ž์‹ ๋ณด๋‹ค ํฐ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋ผˆ๋Œ€ ๋งŒ๋“ค๊ธฐ

TreeNode

import Foundation

final class TreeNode<T: Comparable> {
    private(set) var data: T
    var leftChild: TreeNode?
    var rightChild: TreeNode?
    
    var isLeafNode: Bool {
        return self.leftChild == nil && self.rightChild == nil
    }
    var hasSingleChild: Bool {
        return (self.leftChild != nil && self.rightChild == nil)
        || (self.leftChild == nil && self.rightChild != nil)
    }
    var hasTwoChild: Bool {
        return self.leftChild != nil && self.rightChild != nil
    }
    
    init(data: T) {
        self.data = data
    }
    
    func update(data: T) {
        self.data = data
    }
    
    var asString:String { return treeString(self){("\($0.data)",$0.leftChild,$0.rightChild)}  }
}

๋จผ์ € ํŠธ๋ฆฌ์— ์‚ฌ์šฉ๋  ๋…ธ๋“œ๋ฅผ ๋งŒ๋“ค์–ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ฒƒ์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๋ณ€์ˆ˜, ์™ผ์ชฝ ์ž์‹ ๋…ธ๋“œ์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ, ๊ทธ๋ฆฌ๊ณ  ์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ์ž…๋‹ˆ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  ๋…ธ๋“œ์˜ ์ƒํƒœ๋ฅผ ์ฒดํฌํ•  ์ˆ˜ ์žˆ๋Š” ์„ธ ๊ฐ€์ง€ ํ”„๋กœํผํ‹ฐ๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ๋…ธ๋“œ์˜ ์ž์‹๋…ธ๋“œ ์œ ๋ฌด์— ๋”ฐ๋ผ์„œ ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์—†๋Š” ๋ฆฌํ”„ ๋…ธ๋“œ์ธ์ง€, ์ž์‹ ๋…ธ๋“œ๊ฐ€ ํ•˜๋‚˜์ธ์ง€, ๋‘ ๊ฐœ์ธ์ง€ ํ™•์ธํ•ด์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฐ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์™œ ํ•„์š”ํ•œ์ง€๋Š” ์ž ์‹œํ›„์— ๋‹ค์‹œ ์„ค๋ช…ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. 

 

์ถ”๊ฐ€์ ์œผ๋กœ ํ˜„์žฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋กœ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๋ฉ”์„œ๋“œ๋„ ๋งŒ๋“ค์–ด์ฃผ์—ˆ๋Š”๋ฐ์š”, ์ด ๋ฉ”์„œ๋“œ ์—ญ์‹œ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉ๋˜๋Š”์ง€ ์ž ์‹œํ›„์— ์„ค๋ช…ํ• ๊ฒŒ์š”!

 

asString ํ”„๋กœํผํ‹ฐ๋Š” ํŠธ๋ฆฌ๋ฅผ ์—„์ฒญ ์˜ˆ์˜๊ฒŒ ์ถœ๋ ฅํ•ด์ฃผ๋Š” treeString ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š”๋ฐ ์ด๊ฑด ์Šคํƒ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ์—์„œ ์ง„์งœ ์ž˜ ๋งŒ๋“ค์–ด์ฃผ์‹  ๋ถ„์ด ๊ณ„์…”์„œ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ–ˆ์–ด์š”!

 

์ด ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋‹ต๋ณ€์— ๋ฉ”์„œ๋“œ๊ฐ€ ์ •์˜๋˜์–ด ์žˆ๊ตฌ์š”,

 

How to “draw” a Binary Tree in Console?

How can I print a binary tree in Swift so that the input 79561 prints output like this: 7 / \ 5 9 / \ 1 6 I tried to arrange this with some code using For Loops and If Statements bu...

stackoverflow.com

 

์ ์šฉํ•˜๋ฉด ์ด๋ ‡๊ฒŒ ์˜ˆ์˜๊ฒŒ ์ฝ˜์†”์— ํŠธ๋ฆฌ๊ฐ€ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค!

ํƒ์ƒ‰(Search) - O(log N) 

์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ์˜ ํŠน์ง•์ด ์–ด๋–ค ๋…ธ๋“œ์˜ ์™ผ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ๋Š” ํ•ญ์ƒ ์ž์‹ ๋ณด๋‹ค ์ž‘์€ ๊ฐ’๋“ค์ด ์žˆ๊ณ , ์˜ค๋ฅธ์ชฝ์—๋Š” ํ•ญ์ƒ ์ž์‹ ๋ณด๋‹ค ํฐ ๊ฐ’๋“ค์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ํƒ์ƒ‰๋„ ์ด๋ฅผ ์ด์šฉํ•ด์„œ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

์ด ํŠธ๋ฆฌ์—์„œ 5๋ฅผ ๊ฐ’์œผ๋กœ ๊ฐ€์ง„ ๋…ธ๋“œ๋ฅผ ์ฐพ์•„๊ฐ€๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ์š”? ํŠธ๋ฆฌ์ด๋‹ˆ๊นŒ ์ผ๋‹จ ๋ฃจํŠธ๋…ธ๋“œ์—์„œ ์‹œ์ž‘ํ•ด์•ผ๊ฒ ์ฃ ?

 

๋ฃจํŠธ ๋…ธ๋“œ์˜ ๊ฐ’์ธ 4์™€ ์ฐพ๊ณ ์ž ํ•˜๋Š” ๋…ธ๋“œ์˜ ๊ฐ’์ธ 5๋ฅผ ๋น„๊ตํ•ด๋ด…์‹œ๋‹ค. ์ฐพ๊ณ ์ž ํ•˜๋Š” ๋…ธ๋“œ์˜ ๋” ๊ฐ’์ด ํฌ๋„ค์š”. ๊ทธ๋Ÿผ ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ์˜ ๊ทœ์น™๋Œ€๋กœ ์™ผ์ชฝ ์„œ๋ธŒ ํŠธ๋ฆฌ๋Š” ํƒ์ƒ‰ํ•  ํ•„์š”์—†์ด ์˜ค๋ฅธ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ๋กœ ์ด๋™ํ•ฉ์‹œ๋‹ค!

 

์ด๋ฒˆ์—” ์ƒˆ๋กœ์šด ๋ฃจํŠธ ๋…ธ๋“œ์™€ ๊ทธ ๊ฐ’์ธ 6์„ ๋งŒ๋‚˜๊ฒŒ๋ฉ๋‹ˆ๋‹ค. 6์€ ์ฐพ๊ณ ์ž ํ•˜๋Š” ๋…ธ๋“œ์˜ ๊ฐ’๋ณด๋‹ค ํฌ๊ธฐ ๋•Œ๋ฌธ์— ํ˜„์žฌ ๋ฃจํŠธ๋…ธ๋“œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์˜ค๋ฅธ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ๋Š” ํƒ์ƒ‰ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์™ผ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ๋กœ ์ด๋™ํ• ๊ฒŒ์š”!

์ด๋ฒˆ์—๋Š” ์ƒˆ๋กœ์šด ๋ฃจํŠธ ๋…ธ๋“œ์˜ ๊ฐ’์ด ์ฐพ๊ณ ์žํ•˜๋Š” ๊ฐ’๊ณผ ๊ฐ™๋„ค์š”! ๊ทธ๋Ÿผ ์ด ๋…ธ๋“œ์˜ ์ฐธ์กฐ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋ฉด ์›ํ•˜๋Š” ๋…ธ๋“œ์˜ ํƒ์ƒ‰์„ ๋งˆ์น˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์ด๋ฒˆ ๋…ธ๋“œ์˜ ๊ฐ’์ด 5๊ฐ€ ์•„๋‹ˆ์—ˆ๋‹ค๋ฉด nil์„ ๋งŒ๋‚˜๋ฉด์„œ ํƒ์ƒ‰์ด ์ข…๋ฃŒ๋˜๊ฒ ์ฃ ?

 

์œ„ ๊ณผ์ •์„ ์ฝ”๋“œ๋กœ ์ ์œผ๋ฉด ์ด๋ ‡์Šต๋‹ˆ๋‹ค.

    private func search(data: T, in node: TreeNode<T>?) -> TreeNode<T>? {
        if node == nil || node?.data == data { return node }
        
        return node!.data > data
        ? search(data: data, in: node?.leftChild)
        : search(data: data, in: node?.rightChild)
    }

ํ˜„์žฌ ๋ฃจํŠธ ๋…ธ๋“œ(node)์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์ฐพ๋Š” ๋ฐ์ดํ„ฐ์˜ ๊ฐ’๋ณด๋‹ค ํฌ๋ฉด ์™ผ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ๋กœ ์žฌ๊ท€ํ•˜๊ณ , ์ž‘์œผ๋ฉด ์˜ค๋ฅธ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ๋กœ ์žฌ๊ท€ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ˜„์žฌ ๋ฃจํŠธ๋…ธ๋“œ๊ฐ€ nil์ด๊ฑฐ๋‚˜, ๋‘ ๋ฐ์ดํ„ฐ๊ฐ€ ์ผ์น˜ํ•˜๋ฉด ์žฌ๊ท€๋ฅผ ์ข…๋ฃŒํ•˜๊ณ  ํ˜„์žฌ ๋ฃจํŠธ๋…ธ๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. 

 

ํƒ์ƒ‰ํ•˜๋Š” ๊ณผ์ •์—์„œ ํŠธ๋ฆฌ์˜ ํ•œ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ์˜ ํƒ์ƒ‰์„ ๊ณ„์† ์ƒ๋žตํ•˜๋ฉด์„œ ์ง„ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹œ๊ฐ„๋ณต์žก๋„๋Š” ํŠธ๋ฆฌ์˜ ๋†’์ด์— ๋”ฐ๋ฅธ ๋…ธ๋“œ๊ฐœ์ˆ˜์ธ O(log N)์œผ๋กœ ์ •๋ฆฌ๋ฉ๋‹ˆ๋‹ค.

 

ํƒ์ƒ‰  Worst Case - O(N)

ํ•˜์ง€๋งŒ ๋งŒ์•ฝ ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ๊ฐ€ ๋‹ค์Œ์ฒ˜๋Ÿผ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค๋ฉด ์–ด๋–จ๊นŒ์š”?

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

 

์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•ด BBST(Balanced Binary Search Tree)์ธ AVL ํŠธ๋ฆฌ์™€ Red-Black ํŠธ๋ฆฌ๊ฐ€ ๊ณ ์•ˆ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜์ค‘์— ๊ธฐํšŒ๊ฐ€ ๋œ๋‹ค๋ฉด ๊ตฌํ˜„ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค! ๊ฒฐ๋ก ์€ ์ผ๋ฐ˜ ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ๋กœ๋Š” ์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ๋ง‰์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค..

 

์‚ฝ์ž…(add) - O(log N)

๊ฑฐ์˜ ๋ชจ๋“  ์ด์ง„ ํŠธ๋ฆฌ์˜ ์—ฐ์‚ฐ๋“ค์€ ํƒ์ƒ‰์— ์˜์กดํ•ฉ๋‹ˆ๋‹ค. ์‚ฝ์ž… ์—ญ์‹œ๋„ ์ ์ ˆํ•œ ์œ„์น˜์— ์ƒˆ๋กœ์šด ๊ฐ’์„ ๊ฐ€์ง„ ๋…ธ๋“œ๋ฅผ ๋„ฃ์–ด์ฃผ๊ธฐ ์œ„ํ•ด์„œ ํƒ์ƒ‰์„ ์ง„ํ–‰ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

์ด๋ฒˆ์—๋Š” ์ด๋ ‡๊ฒŒ ์ƒ๊ธด ํŠธ๋ฆฌ์— ์ƒˆ๋กœ์šด ๋…ธ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค๊ณ  ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ์— ์ถ”๊ฐ€ํ•  ๋…ธ๋“œ์˜ ๊ฐ’์€ 4์ž…๋‹ˆ๋‹ค. ๋ฃจํŠธ ๋…ธ๋“œ์™€ ๋จผ์ € ๊ฐ’์„ ๋น„๊ตํ•ด๋ด…์‹œ๋‹ค. ์ƒˆ ๋…ธ๋“œ์˜ ๊ฐ’์ด ๋” ์ž‘๋„ค์š”. ์™ผ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ๋กœ ๋“ค์–ด๊ฐ‘์‹œ๋‹ค.

์ด๋ฒˆ์—” ์ƒˆ๋กœ์šด ๋…ธ๋“œ์˜ ๊ฐ’์ด ์„œ๋ธŒํŠธ๋ฆฌ์˜ ๋ฃจํŠธ๋…ธ๋“œ ๋ณด๋‹ค ๋” ํฐ ๊ฒƒ์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ ์˜ค๋ฅธ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ๋กœ ๊ฐ€์•ผ๊ฒ ์ฃ ?

์ƒˆ๋กœ์šด ๋…ธ๋“œ์˜ ๊ฐ’์ด ์„œ๋ธŒํŠธ๋ฆฌ์˜ ๋ฃจํŠธ๋…ธ๋“œ๋ณด๋‹ค ํฝ๋‹ˆ๋‹ค. ์ด์ œ ์˜ค๋ฅธ์ชฝ์œผ๋กœ ์ด๋™ํ•˜๋ ค๊ณ  ํ•˜๋Š”๋ฐ, ํ˜„์žฌ ๋ฃจํŠธ ๋…ธ๋“œ๋Š” ๋ฆฌํ”„ ๋…ธ๋“œ๋ผ์„œ ์˜ค๋ฅธ์ชฝ์— ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ƒˆ๋กœ์šด ๋…ธ๋“œ๋ฅผ ์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ๋กœ ๋งŒ๋“ค์–ด์ฃผ๋ฉด ์ƒˆ๋กœ์šด ๋…ธ๋“œ์˜ ์ถ”๊ฐ€๊ฐ€ ์™„๋ฃŒ๋ฉ๋‹ˆ๋‹ค.

์ด ๊ณผ์ •์—์„œ ๋ณธ ๊ฒƒ์ฒ˜๋Ÿผ ์‹ค์ œ๋กœ ์ƒˆ๋กœ์šด ๋…ธ๋“œ๋ฅผ ํŠธ๋ฆฌ์— ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์€ ์ƒ์ˆ˜์‹œ๊ฐ„์ด์ง€๋งŒ ์ƒˆ๋กœ์šด ์œ„์น˜๋ฅผ ํƒ์ƒ‰ํ•˜๋Š”๋ฐ๊นŒ์ง€ ํƒ์ƒ‰ํ•˜๋Š” ์‹œ๊ฐ„์ด ์š”๊ตฌ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์‹œ๊ฐ„๋ณต์žก๋„๋Š” ํƒ์ƒ‰์˜ ์‹œ๊ฐ„๋ณต์žก๋„์™€ ๋™์ผํ•œ O(log N)์ด ๋ฉ๋‹ˆ๋‹ค.

 

    mutating func add(data: T) {
        let node = TreeNode(data: data)
        if root == nil {
            self.root = node
            return
        }
        self.add(newNode: node, under: root)
    }

    @discardableResult
    private func add(newNode: TreeNode<T>, under parentNode: TreeNode<T>?) -> TreeNode<T>? {
        guard newNode.data != parentNode?.data else { return nil }
        if parentNode == nil {
            return newNode
        }
        parentNode!.data > newNode.data
        ? (parentNode?.leftChild = add(newNode: newNode, under: parentNode?.leftChild))
        : (parentNode?.rightChild = add(newNode: newNode, under: parentNode?.rightChild))
        return parentNode
    }

๊ตฌํ˜„์€ ํƒ์ƒ‰๊ณผ ๋™์ผํ•˜๊ฒŒ ์ง„ํ–‰๋˜์ง€๋งŒ ๋ฆฌํ”„ ๋…ธ๋“œ์˜ ์ž์‹ ๋…ธ๋“œ๋ฅผ ๋งŒ๋‚˜๋ฉด ์ƒˆ๋กœ์šด ๋…ธ๋“œ๋ฅผ ์‚ฝ์ž…ํ•ด์ฃผ๋Š” ๋กœ์ง์ด ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค. 

์‚ญ์ œ - O(log N)

BST์˜ ์ตœ๊ณ  ํ—ท๊ฐˆ๋ฆฌ๋Š” ํฌ์ธํŠธ๋Š” ์‚ญ์ œ ์—ฐ์‚ฐ์ด์ฃ ใ…  ์‚ญ์ œํ•  ๋…ธ๋“œ์˜ ์ž์‹ ๋…ธ๋“œ ๊ฐœ์ˆ˜์— ๋”ฐ๋ผ์„œ ์ด ์„ธ ๊ฐœ์˜ ๊ฒฝ์šฐ๋กœ ๋กœ์ง์ด ๋‹ค๋ฅด๊ฒŒ ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค. 

 

์‚ญ์ œ ์—ฐ์‚ฐ๋„ ์‚ญ์ œํ•  ๋…ธ๋“œ๋ฅผ ๋จผ์ € ์ฐพ์•„๋‚ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํƒ์ƒ‰์ด ์„ ํ–‰๋ฉ๋‹ˆ๋‹ค. ํƒ์ƒ‰์ด ์™„๋ฃŒ๋˜์–ด์„œ ์‚ญ์ œํ•  ๋…ธ๋“œ๋ฅผ ์ฐพ์œผ๋ฉด ๋‹ค์Œ ๊ณผ์ •์„ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

 

1) ์‚ญ์ œํ•  ๋…ธ๋“œ๊ฐ€ ๋ฆฌํ”„๋…ธ๋“œ์ธ ๊ฒฝ์šฐ 

 

๊ฐ€์žฅ ์‰ฌ์šด ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. ๋ฆฌํ”„ ๋…ธ๋“œ์˜ ๊ฒฝ์šฐ์—๋Š” ์™ผ์ชฝ์ด๋‚˜ ์˜ค๋ฅธ์ชฝ์— ๋‹ค๋ฅธ ๋…ธ๋“œ๋“ค์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋ƒฅ ํŠธ๋ฆฌ์—์„œ ๋ฆฌํ”„๋…ธ๋“œ๋งŒ ์ œ๊ฑฐํ•ด์ฃผ๋ฉด ์‚ญ์ œ๊ฐ€ ์™„๋ฃŒ๋ฉ๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•˜์ฃ ? ์ฝ”๋“œ๋กœ ์ž‘์„ฑํ•ด๋ณด๋ฉด ์ด๋ ‡๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

        guard let targetNode = self.search(data: data, in: root) else { return nil }
	
    	// target is leaf node
        if targetNode.isLeafNode {
            let parent = self.findParent(of: targetNode, under: root)
            parent?.rightChild === targetNode
            ? (parent?.rightChild = nil)
            : (parent?.leftChild = nil)
            return targetNode.data
        }

์‚ญ์ œํ•  ๋…ธ๋“œ๋ฅผ ์ฐพ๊ณ  ํ•ด๋‹น ๋…ธ๋“œ์˜ ๋ถ€๋ชจ ๋…ธ๋“œ๊ฐ€ ๊ฐ€์ง„ ์‚ญ์ œํ•  ๋…ธ๋“œ์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ๋ฅผ ์ง€์›Œ์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์‚ฌ์‹ค ํƒ์ƒ‰ํ•˜๋ฉด์„œ ๋ถ€๋ชจ๋…ธ๋“œ๋ฅผ ์ฐพ๋Š”๊ฒŒ ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์ธ๋ฐ ํŽธ์˜์ƒ ๋ฏธ๋ฆฌ ๊ตฌํ˜„๋œ ํƒ์ƒ‰ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์–ด์„œ ๋ถ€๋ชจ ๋…ธ๋“œ๋ฅผ ์ฐพ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๋”ฐ๋กœ ๋งŒ๋“ค์–ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

 

2) ์‚ญ์ œํ•  ๋…ธ๋“œ์—๊ฒŒ ํ•˜๋‚˜์˜ ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ

์ด๋ฒˆ์—๋Š” ์‚ญ์ œํ•  ๋…ธ๋“œ๊ฐ€ ์ž์‹ ๋…ธ๋“œ๋ฅผ ์™ผ์ชฝ์ด๋‚˜ ์˜ค๋ฅธ์ชฝ์— ํ•˜๋‚˜๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. ์ด๋Œ€๋กœ ๋…ธ๋“œ๋ฅผ ์‚ญ์ œํ•˜๋ฉด ์•„๋ž˜์— ๋”ธ๋ ค์žˆ๋˜ ์„œ๋ธŒ ํŠธ๋ฆฌ์— ์†ํ•˜๋Š” ๋ชจ๋“  ๋…ธ๋“œ๊ฐ€ ์‚ญ์ œ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ญ์ œํ•  ๋…ธ๋“œ๊ฐ€ ๊ฐ€์ง„ ํ•˜๋‚˜์˜ ์„œ๋ธŒํŠธ๋ฆฌ๋ฅผ ๊ธฐ์กด ํŠธ๋ฆฌ์— ์—ฐ๊ฒฐ์‹œ์ผœ์ฃผ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

์™ผ์ชฝ์— ์ž์‹๋…ธ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฐ’์ด 2์ธ ๋…ธ๋“œ๋ฅผ ์‚ญ์ œํ•ด๋ด…์‹œ๋‹ค.

์‚ญ์ œํ•  ๋…ธ๋“œ์˜ ๋ถ€๋ชจ ๋…ธ๋“œ๋ฅผ ์ฐพ๊ณ  ํ•ด๋‹น ๋…ธ๋“œ์˜ ์ž์‹ ๋…ธ๋“œ๋ฅผ ์‚ญ์ œํ•  ๋…ธ๋“œ์˜ ์ž์‹ ๋…ธ๋“œ๋กœ ๋ณ€๊ฒฝํ•ด์ค๋‹ˆ๋‹ค. ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฏธ ์™ผ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ๋Š” ๋ชจ๋‘ ์‚ญ์ œํ•  ๋…ธ๋“œ์˜ ๋ถ€๋ชจ ๋…ธ๋“œ๋ณด๋‹ค ์ž‘์€ ๊ฐ’๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ํŠธ๋ฆฌ๋ฅผ ์žฌ์กฐ์ •ํ•ด ์ค„ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

 

        guard let targetNode = self.search(data: data, in: root) else { return nil }
       
       // target has single child node 
        if targetNode.hasSingleChild {
            let child = targetNode.leftChild != nil ? targetNode.leftChild : targetNode.rightChild
            guard let parent = self.findParent(of: targetNode, under: root) else { return nil }
            parent.data > child!.data ? (parent.leftChild = child) : (parent.rightChild = child)
            return targetNode.data
        }

์ฝ”๋“œ๋กœ ๊ตฌํ˜„ํ•  ๋•Œ๋„ ์–ด๋ ต์ง€ ์•Š๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์‚ญ์ œํ•  ๋…ธ๋“œ์˜ ๋ถ€๋ชจ ๋…ธ๋“œ๋ฅผ ์ฐพ์•„ ์ž์‹ ๋…ธ๋“œ ์ •๋ณด๋ฅผ ๋ณ€๊ฒฝํ•ด์ฃผ๋Š” ๊ฒƒ์œผ๋กœ ์‰ฝ๊ฒŒ ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

 

3) ์‚ญ์ œํ•  ๋…ธ๋“œ์—๊ฒŒ ๋‘ ๊ฐœ์˜ ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ

๋ฌธ์ œ๋Š” ์‚ญ์ œํ•  ๋…ธ๋“œ๊ฐ€ ๋‘ ๊ฐœ์˜ ์ž์‹๋…ธ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.

์ด๋ฒˆ์—๋Š” ์ด ํŠธ๋ฆฌ์˜ ๋ฃจํŠธ ๋…ธ๋“œ๋ฅผ ์‚ญ์ œํ•œ๋‹ค๊ณ  ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ฃจํŠธ๋…ธ๋“œ๋ฅผ ์‚ญ์ œํ•˜๋ฉด์„œ ์–‘์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ๋“ค์„ ์—ฐ๊ฒฐํ•ด์•ผ๋˜๋Š”๋ฐ์š”, ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ์—ฐ๊ฒฐํ•ด์ค„ ์ˆ˜ ์žˆ์„๊นŒ์š”?

 

์‚ญ์ œ๋  ๋…ธ๋“œ์˜ ์–‘์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ๋ฅผ ์—ฐ๊ฒฐํ•  ๋…ธ๋“œ๋Š” ์™ผ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ์˜ ๊ฐ’๋ณด๋‹ค๋Š” ์ปค์•ผํ•˜๊ณ , ์˜ค๋ฅธ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ์˜ ๊ฐ’๋ณด๋‹ค๋Š” ์ž‘์•„์•ผํ•ฉ๋‹ˆ๋‹ค. 

 

์ด ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๋…ธ๋“œ๋Š” ์˜ค๋ฅธ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ ๊ฐ€์žฅ ์™ผ์ชฝ์— ์žˆ๋Š” ๋…ธ๋“œ๋ฅผ ์ฐพ์•„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ค๋ฅธ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ๋Š” ํ•ญ์ƒ ์™ผ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ๋ณด๋‹ค ๊ฐ’์ด ํฌ๊ณ , ์˜ค๋ฅธ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ์˜ ๊ฐ€์žฅ ์™ผ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ๋Š” ๊ทธ ์ค‘์—์„œ๋„ ๊ฐ€์žฅ ์ž‘์€ ๊ฐ’์ด๊ธฐ ๋•Œ๋ฌธ์— ์™ผ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ์˜ ๋ฆฌํ”„ ๋…ธ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ์–‘์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ๋ฅผ ์—ฐ๊ฒฐ์‹œ์ผœ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ด๋ ‡๊ฒŒ ์‚ญ์ œํ•  ๋…ธ๋“œ์˜ ์˜ค๋ฅธ์ชฝ ์ž์‹์˜ ์„œ๋ธŒํŠธ๋ฆฌ์— ์žˆ๋Š” ๊ฐ€์žฅ ์ž‘์€ ๊ฐ’์„ ๊ฐ€์ง„ ๋…ธ๋“œ๋ฅผ Successor ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์‚ญ์ œํ•  ๋…ธ๋“œ์˜ ์œ„์น˜๋ฅผ ๊ณ„์Šน๋ฐ›์„ ๋…ธ๋“œ๋ผ๋Š” ์˜๋ฏธ์ธ ๊ฒƒ ๊ฐ™๋„ค์š”.

 

์‚ญ์ œํ•  ๋…ธ๋“œ์˜ ์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ๋กœ ๋จผ์ € ์ด๋™ํ•˜๊ณ , ํ•ด๋‹น ๋…ธ๋“œ์˜ ์™ผ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ๋ฅผ ๊ณ„์† ๋”ฐ๋ผ๊ฐ€๋ฉด,

๊ฐ’์ด 7์ธ ๋…ธ๋“œ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

 

์ด์ œ ์ด ๋…ธ๋“œ๊ฐ€ ๊ฐ€์ง„ ๊ฐ’์„ ๋ฃจํŠธ๋…ธ๋“œ์— ๋ฎ์–ด์”Œ์›Œ์ค์‹œ๋‹ค.

์‹ค์ œ๋กœ ๋…ธ๋“œ๋ฅผ ๊ตํ™˜ํ•˜๋Š” ๊ฒƒ๋„ ์ข‹๊ฒ ์ง€๋งŒ ํ‚ค๋กœ ์‚ฌ์šฉ๋˜๋Š” ๋…ธ๋“œ์˜ ๊ฐ’์œผ๋กœ ๋ฎ์–ด์”Œ์›Œ๋„ ๋ฌด๋ฐฉํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋…ธ๋“œ ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ญ์ œ ์ดํ›„์— ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ํ•œ๋‹ค๋ฉด ๋…ธ๋“œ ์ž์ฒด๋ฅผ ๊ตํ™˜ํ•ด์•ผ๊ฒ ์ฃ ?

๊ทธ๋ฆฌ๊ณ  Successor๋กœ ์‚ฌ์šฉ๋œ ๋…ธ๋“œ๋ฅผ ์ง€์›Œ์ฃผ๋ฉด, ๋ชฉํ‘œ ๋…ธ๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ ๋„ ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

        // target has two child nodes
        if targetNode.hasTwoChild {
            let deleted = targetNode.data
            guard let successor = self.findSuccessor(of: targetNode.rightChild) else { return nil }
            if !successor.isLeafNode {
                let parent = self.findParent(of: successor, under: root)
                parent?.leftChild = successor.rightChild
            }
            _ = self.delete(data: successor.data)
            targetNode.update(data: successor.data)
            return deleted
        }

์ฝ”๋“œ๋กœ๋Š” ์ด๋ ‡๊ฒŒ ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค. ๋จผ์ € Successor๋ฅผ ์ฐพ์•„์„œ ๊ฐ’์„ ๋ฎ์–ด์”Œ์šด ๋’ค์—, Successor์˜ ๋ถ€๋ชจ๋…ธ๋“œ๋ฅผ ์ฐพ์•„์„œ ์ž์‹ ๋…ธ๋“œ์˜ ์ฐธ์กฐ๋ฅผ ์ œ๊ฑฐํ•ด์ค๋‹ˆ๋‹ค.

 

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

 

์ „์ฒด ์ฝ”๋“œ

 

 

GitHub - jeonyeohun/Data-Structures-In-Swift: ๐Ÿ‘ท๐Ÿป‍โ™‚๏ธ STL ์™œ ์—†์–ด.. ์Šค์œ„ํ”„ํŠธ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ

๐Ÿ‘ท๐Ÿป‍โ™‚๏ธ STL ์™œ ์—†์–ด.. ์Šค์œ„ํ”„ํŠธ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ. Contribute to jeonyeohun/Data-Structures-In-Swift development by creating an account on GitHub.

github.com

์ž๋ฃŒ๊ตฌ์กฐ ์‹œ๋ฆฌ์ฆˆ์˜ ์ฝ”๋“œ๋“ค์€ ์ด ๋ ˆํฌ์—์„œ ๋ชจ๋‘ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด์š”!