๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ–ฅ Computer Science/Data Structure

[Data Structure] AVL ํŠธ๋ฆฌ ๊ตฌํ˜„ํ•ด๋ณด๊ธฐ (feat. Swift)

by Fomagran ๐Ÿ’ป 2021. 12. 6.
728x90
๋ฐ˜์‘ํ˜•

 

์•ˆ๋…•ํ•˜์„ธ์š” Foma ๐Ÿ’ป ์ž…๋‹ˆ๋‹ค!

 

์ €๋ฒˆ ์‹œ๊ฐ„์— AVL ํŠธ๋ฆฌ๊ฐ€ ๋ญ”์ง€ ์ด๋ก ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•˜๋Š”๋ฐ์š”.

 

(ํ˜น์‹œ ์•ˆ๋ณด์‹  ๋ถ„๋“ค์€ ์—ฌ๊ธฐ ์—์„œ ํ™•์ธํ•ด์ฃผ์„ธ์š”!)

 

์˜ค๋Š˜์€ AVL ํŠธ๋ฆฌ๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•ด๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

 

๋ฐ”๋กœ ์‹œ์ž‘ํ• ๊ฒŒ์š”~


AVLNode

 

๊ธฐ๋ณธ์ ์œผ๋กœ ์ด์ง„ํƒ์ƒ‰ํŠธ๋ฆฌ์˜ ๋…ธ๋“œ์™€ ๋˜‘๊ฐ™์ง€๋งŒ ์™ผ์ชฝ๊ณผ,์˜ค๋ฅธ์ชฝ ์ž์‹์˜ ๋†’์ด์™€ ๋ฐธ๋Ÿฐ์Šค ํŒฉํ„ฐ๋ฅผ ์ธก์ •ํ•  ๋ณ€์ˆ˜๋ฅผ ๋”ฐ๋กœ

 

๋งŒ๋“ค์–ด์—ˆ์Šต๋‹ˆ๋‹ค.

 

class AVLNode<T:Comparable> {
    var value:T
    var leftChild:AVLNode?
    var rightChild:AVLNode?
    var height:Int = 0

    var leftHeight:Int {
        return leftChild?.height ?? -1
    }
    
    var rightHeight:Int {
        return rightChild?.height ?? -1
    }
    
    var balanceFactor:Int {
        return leftHeight - rightHeight
    }
    
    init(value:T) {
        self.value = value
    }
}

extension AVLNode {
    var min: AVLNode {
        return leftChild?.min ?? self
    }
}

Balance

 

๊ท ํ˜•์ธ์ง€ ์•„๋‹Œ์ง€๋ฅผ ์ฒดํฌํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค.

 

์ ˆ๋Œ€๊ฐ’์ด 2์ธ์ง€ ์•„๋‹Œ์ง€๋ฅผ ์ฒดํฌํ•ด์ค๋‹ˆ๋‹ค.

 

 private func isBalanced(_ node: AVLNode<T>) -> Bool {
        return abs(node.balanceFactor) != 2
    }

 

๋งŒ์•ฝ ๊ท ํ˜•์ด ์žกํžˆ์ง€ ์•Š์•˜๋‹ค๋ฉด ๊ท ํ˜•์„ ์žก์•„์ค˜์•ผ๊ฒ ์ฃ ?

 

๋ฐธ๋Ÿฐ์ŠคํŒฉํ„ฐ๊ฐ€ 2๋ผ๋ฉด ์™ผ์ชฝ์œผ๋กœ ์น˜์šฐ์ณ์ง„ ๊ฒƒ์ด๊ณ  -2๋ผ๋ฉด ์˜ค๋ฅธ์ชฝ์œผ๋กœ ์น˜์šฐ์ณ์ง„ ๊ฒƒ์ด๋ฏ€๋กœ

 

๋ฐธ๋Ÿฐ์Šค ํŒฉํ„ฐ์— ๋งž๊ฒŒ ๊ท ํ˜•์„ ๋งž์ถฐ์ค๋‹ˆ๋‹ค.

 

 private func makeBalanced(_ node: AVLNode<T>) -> AVLNode<T> {
        if node.balanceFactor == 2 {
            return leftBalanced(node)
        }else {
            return rightBalanced(node)
        }
    }

 

 

์™ผ์ชฝ์œผ๋กœ ์น˜์šฐ์ณ ์žˆ๋Š” ๊ฒฝ์šฐ ์™ผ์ชฝ ์ž์‹์˜ ๋ฐธ๋Ÿฐ์Šค ํŒฉํ„ฐ๊ฐ€ -1์ด๋ผ๋ฉด ์˜ค๋ฅธ์ชฝ์— ์ž์‹์ด ์žˆ๋Š” ๊ฒƒ์ด๋ฏ€๋กœ 

 

์™ผ์ชฝ์œผ๋กœ ํšŒ์ „์„ ํ•˜๊ณ  ์˜ค๋ฅธ์ชฝ์œผ๋กœ ํšŒ์ „์„ ํ•ด์„œ ๊ท ํ˜•์„ ๋งž์ถฐ์ค๋‹ˆ๋‹ค.

 

๊ทธ๊ฒŒ ์•„๋‹ˆ๋ผ๋ฉด ๊ทธ๋ƒฅ ์˜ค๋ฅธ์ชฝ์œผ๋กœ ํšŒ์ „ํ•ด์„œ ๊ท ํ˜•์„ ๋งž์ถฐ์ค๋‹ˆ๋‹ค.

 

  private func leftBalanced(_ node: AVLNode<T>) -> AVLNode<T> {
        if let leftChild = node.leftChild, leftChild.balanceFactor == -1 {
            return leftRightRotate(node)
        }else {
            return rightRotate(node)
        }
    }

 

์˜ค๋ฅธ์ชฝ์œผ๋กœ ์น˜์šฐ์ณ ์žˆ๋Š” ๊ฒฝ์šฐ ์˜ค๋ฅธ์ชฝ ์ž์‹์˜ ๋ฐธ๋Ÿฐ์Šค ํŒฉํ„ฐ๊ฐ€ 1์ด๋ผ๋ฉด ์™ผ์ชฝ์— ์ž์‹์ด ์žˆ๋Š” ๊ฒƒ์ด๋ฏ€๋กœ

 

์˜ค๋ฅธ์ชฝ์œผ๋กœ ํšŒ์ „์„ ํ•˜๊ณ  ์™ผ์ชฝ์œผ๋กœ ํšŒ์ „์„ ํ•ด์„œ ๊ท ํ˜•์„ ๋งž์ถฐ์ค๋‹ˆ๋‹ค.

 

๊ทธ๊ฒŒ ์•„๋‹ˆ๋ผ๋ฉด ๊ทธ๋ƒฅ ์™ผ์ชฝ์œผ๋กœ ํšŒ์ „ํ•ด์„œ ๊ท ํ˜•์„ ๋งž์ถฐ์ค๋‹ˆ๋‹ค.

 

  private func rightBalanced(_ node: AVLNode<T>) -> AVLNode<T> {
        if let rightChild = node.rightChild, rightChild.balanceFactor == 1 {
            return rightLeftRotate(node)
        }else {
            return leftRotate(node)
        }
    }

Rotate

Right

 

์™ผ์ชฝ์œผ๋กœ ์น˜์šฐ์ณ์ ธ ์žˆ๋Š” ๊ฒฝ์šฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์˜ค๋ฅธ์ชฝ์œผ๋กœ ํšŒ์ „ํ•ด์„œ ๊ท ํ˜•์„ ๋งž์ถฐ์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

 

 

 

ํšŒ์ „ํ•ด์ฃผ๋Š” ๋ฐฉ๋ฒ•์€ ๊ฐ€์žฅ ์ฒซ ๋ฒˆ์งธ ๋…ธ๋“œ๋ฅผ ์ค‘์•™๊ฐ’์˜ ์˜ค๋ฅธ์ชฝ ์ž์‹์œผ๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

 

์ค‘์•™๊ฐ’์€ ๋‘ ๋ฒˆ์งธ ๊ฐ’์ด๋ฏ€๋กœ ์ฒซ ๋ฒˆ์งธ ๋…ธ๋“œ์˜ ์™ผ์ชฝ ์ž์‹์ด ๋˜๊ฒ ์ฃ ?

 

๊ท ํ˜•์„ ๋งž์ถฐ์คฌ์œผ๋‹ˆ ๋…ธ๋“œ์˜ ๋†’์ด๋ฅผ ์กฐ์ •ํ•ด์ค๋‹ˆ๋‹ค.

 

  private func rightRotate(_ node: AVLNode<T>) -> AVLNode<T> {
        let middle = node.leftChild!
        node.leftChild = middle.rightChild
        middle.rightChild = node
        node.height = max(node.leftHeight, node.rightHeight) + 1
        middle.height = max(middle.leftHeight, middle.rightHeight) + 1
        return middle
    }

 

Left

 

์˜ค๋ฅธ์ชฝ์œผ๋กœ ์น˜์šฐ์ณ ์žˆ๋Š” ๊ฒฝ์šฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์™ผ์ชฝ์œผ๋กœ ํšŒ์ „ํ•ด์„œ ๊ท ํ˜•์„ ๋งž์ถฐ์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

 

 

ํšŒ์ „ํ•ด์ฃผ๋Š” ๋ฐฉ๋ฒ•์€ ๊ฐ€์žฅ ์ฒซ ๋ฒˆ์งธ ๋…ธ๋“œ๋ฅผ ์ค‘์•™๊ฐ’์˜ ์™ผ์ชฝ ์ž์‹์œผ๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  ์˜ค๋ฅธ์ชฝ์œผ๋กœ ํšŒ์ „ํ–ˆ์„ ๋•Œ์™€ ๋™์ผํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.

 private func leftRotate(_ node: AVLNode<T>) -> AVLNode<T>{
        let middle = node.rightChild!
        node.rightChild = middle.leftChild
        middle.leftChild = node
        node.height = max(node.leftHeight, node.rightHeight) + 1
        middle.height = max(middle.leftHeight, middle.rightHeight) + 1
        return middle
    }

 

Right-Left

 

์•„๋ž˜ ์ฒซ ๋ฒˆ์งธ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด ">" ๋ฅผ ํšŒ์ „ํ•ด์ฃผ๋Š” ๋ฐฉ๋ฒ•์€ ๋จผ์ € ๋‘ ๋ฒˆ์งธ์™€ ์„ธ ๋ฒˆ์งธ ๋…ธ๋“œ๋ฅผ ์˜ค๋ฅธ์ชฝ์œผ๋กœ ํšŒ์ „ํ•ด์ค€ ๋’ค 

 

์™ผ์ชฝ์œผ๋กœ ํšŒ์ „ํ•ด์ค๋‹ˆ๋‹ค.

 

 

 

์˜ค๋ฅธ์ชฝ ์ž์‹์„ ๊ธฐ์ค€์œผ๋กœ ์˜ค๋ฅธ์ชฝ์œผ๋กœ ํšŒ์ „ํ•ด์ค€ ๋’ค ์™ผ์ชฝ์œผ๋กœ ํšŒ์ „ํ•ด์ค๋‹ˆ๋‹ค.

 

  private func rightLeftRotate(_ node: AVLNode<T>) -> AVLNode<T> {
        node.rightChild = rightRotate(node.rightChild!)
        return leftRotate(node)
    }

 

Left-Right

 

Right-Left์™€ ๋™์ผํ•˜๊ฒŒ "<" ๋ฅผ ํšŒ์ „ํ•ด์ฃผ๋Š” ๋ฐฉ๋ฒ•์€ ๋จผ์ € ๋‘ ๋ฒˆ์งธ์™€ ์„ธ ๋ฒˆ์งธ ๋…ธ๋“œ๋ฅผ ์™ผ์ชฝ์œผ๋กœ ํšŒ์ „ํ•ด์ค€ ๋’ค

 

์˜ค๋ฅธ์ชฝ์œผ๋กœ ํšŒ์ „ํ•ด์ค๋‹ˆ๋‹ค.

 

 

 

  private func leftRightRotate(_ node: AVLNode<T>) -> AVLNode<T> {
        node.leftChild = leftRotate(node.leftChild!)
        return rightRotate(node)
    }

Insert

 

์‚ฝ์ž…์„ ํ•  ๋•Œ ์žฌ๊ท€๋ฅผ ์ด์šฉํ•ด์„œ ๊ท ํ˜•์ด ๋งž๋Š”์ง€ ์•„๋‹Œ์ง€ ํ™•์ธ์„ ํ•ด์ค๋‹ˆ๋‹ค.

 

  public mutating func insert(value: T) {
        root = insert(from: root, value: value)
    }
    
    private func insert(from node: AVLNode<T>?, value: T) -> AVLNode<T> {
        guard var node = node else {
            return AVLNode(value: value)
        }
        if value < node.value {
            node.leftChild = insert(from: node.leftChild, value: value)
        } else {
            node.rightChild = insert(from: node.rightChild, value: value)
        }
        if !isBalanced(node) {
            node = makeBalanced(node)
        }
        node.height = max(node.leftHeight, node.rightHeight) + 1
        return node
    }

Remove

 

์‚ฝ์ž…๊ณผ ๋™์ผํ•˜๊ฒŒ ์žฌ๊ท€๋ฅผ ์ด์šฉํ•ด ๊ท ํ˜•์ด ๋งž๋Š”์ง€ ์•„๋‹Œ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

 

   public mutating func remove(_ value: T) {
        root = remove(node: root, value: value)
    }
    
    private func remove(node: AVLNode<T>?, value: T) -> AVLNode<T>? {
        guard var node = node else {
            return nil
        }
        if value == node.value {
            if node.leftChild == nil && node.rightChild == nil {
                return nil
            }
            if node.leftChild == nil {
                return node.rightChild
            }
            if node.rightChild == nil {
                return node.leftChild
            }
            node.value = node.rightChild!.min.value
            node.rightChild = remove(node: node.rightChild, value: node.value)
        } else if value < node.value {
            node.leftChild = remove(node: node.leftChild, value: value)
        } else {
            node.rightChild = remove(node: node.rightChild, value: value)
        }
        if !isBalanced(node) {
            node = makeBalanced(node)
        }
        node.height = max(node.leftHeight, node.rightHeight) + 1
        return node
    }

Test

 

7,4,3,2,5,8,10,11,9 ์ˆœ์œผ๋กœ ์ˆซ์ž๋ฅผ ์‚ฝ์ž…ํ•˜๊ณ  ์ถœ๋ ฅ์„ ํ•˜๋ฉด ๊ท ํ˜•์ด ์žกํžŒ ํŠธ๋ฆฌ๊ฐ€ ๋‚˜์˜ค๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

        var avl = AVLTree<Int>()
        avl.insert(value: 7)
        avl.insert(value: 4)
        avl.insert(value: 3)
        avl.insert(value: 2)
        avl.insert(value: 5)
        avl.insert(value: 8)
        avl.insert(value: 10)
        avl.insert(value: 11)
        avl.insert(value: 9)

//        4
//    3        8
//  2        7    10
//         5     9   11

 

์œ„์—์„œ 8์„ ์‚ญ์ œํ•˜๊ณ  ์ถœ๋ ฅ์„ ํ•ด๋„ ์ •์ƒ์ ์œผ๋กœ ๊ท ํ˜•์žกํžŒ ํŠธ๋ฆฌ๊ฐ€ ๋‚˜์˜ค๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

        avl.remove(8)
//        4
//    3        9
//  2        7    10
//         5        11

Reference

 

 

[์Šค์œ„ํ”„ํŠธ : ์ž๋ฃŒ๊ตฌ์กฐ] AVL Tree: ์ž๊ฐ€ ๊ท ํ˜• ํŠธ๋ฆฌ: #balance: #ํŠธ๋ฆฌ์˜ ๋†’์ด: #rotation๋ฉ”์†Œ๋“œ: #์„ฑ๋Šฅ์˜ค์ง

์•ˆ๋…•ํ•˜์„ธ์š” !  ์”ฉ์ด ์ž…๋‹ˆ๋‹ค! ์ €๋Š” Swift ์™€ iOS ๋ฅผ ๊ณต๋ถ€ํ•˜๊ณ  ์—ฐ๊ตฌํ•˜๋Š” ๋Œ€๋”ฉ ( ๋Œ€ํ•™์ƒ ) ์ด๊ตฌ์š”! ๊ฐ™์€ ๋ถ„์•ผ๋ฅผ ๊ณต๋ถ€ํ•˜๋Š” ๋ถ„๋“ค์—๊ฒŒ ์กฐ๊ธˆ์ด๋ผ๋„ ๋„์›€์ด ์ฃผ๊ณ  ์‹ถ์–ด์„œ ๊ณต๋ถ€ํ•˜๋Š” ๊ฒƒ๋“ค์„ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค. ์ œ

the-brain-of-sic2.tistory.com

728x90
๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€