๐Ÿ“–Binary Search Tree

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์กฐ๊ฑด์ด ๋ถ™์€ ์ด์ง„ ํŠธ๋ฆฌ

  1. ์™ผ์ชฝ ์ž์‹ ๋…ธ๋“œ์—๋Š” ์ž์‹ ๋ณด๋‹ค ์ž‘์€ ๊ฐ’
  2. ์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ์—๋Š” ์ž์‹ ๋ณด๋‹ค ํฐ ๊ฐ’
  3. ๋ชจ๋“  ๋…ธ๋“œ๋Š” ์œ ์ผํ•œ ๊ฐ’์„ ๊ฐ€์ง

  • ์ด์ง„ํƒ์ƒ‰์˜ ํšจ์œจ์ ์ธ ํƒ์ƒ‰์„ ์œ ์ง€ํ•˜๋ฉด์„œ๋„, ๋นˆ๋ฒˆํ•œ ์‚ฝ์ž…/์‚ญ์ œ๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๊ณ ์•ˆ๋จ

๐Ÿ“–์ˆœํšŒ ๋ฐฉ๋ฒ•

  • ๋ถ€๋ชจ ๋…ธ๋“œ์™€ ์™ผ์ชฝ ๋…ธ๋“œ, ์˜ค๋ฅธ์ชฝ ๋…ธ๋“œ๋ฅผ ์–ด๋–ค ์ˆœ์„œ๋กœ ๋ฐฉ๋ฌธํ•˜๋А๋ƒ์— ๋”ฐ๋ผ ๋‚˜๋ˆ ์ง
  • ์ˆœํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์žฌ๊ท€์  ( โˆต ๊ฐ ๋…ธ๋“œ๋Š” ์„œ๋ธŒ ํŠธ๋ฆฌ)

1. ์ „์œ„ ์ˆœํšŒ(Preorder Traversal)

ํ˜„์žฌ ๋…ธ๋“œ-์™ผ์ชฝ ๋…ธ๋“œ-์˜ค๋ฅธ์ชฝ ๋…ธ๋“œ ์ˆœ์œผ๋กœ ์ˆœํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•

์ˆœํšŒ ๊ฒฐ๊ณผ : A โ†’ B โ†’ D โ†’ G โ†’ E โ†’ C โ†’ F

2. ์ค‘์œ„ ์ˆœํšŒ(Inorder Traversal)

์™ผ์ชฝ ๋…ธ๋“œ-ํ˜„์žฌ ๋…ธ๋“œ-์˜ค๋ฅธ์ชฝ ๋…ธ๋“œ ์ˆœ์œผ๋กœ ์ˆœํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•

์ˆœํšŒ ๊ฒฐ๊ณผ : G โ†’ D โ†’ B โ†’ E โ†’ A โ†’ F โ†’ C

  • ์ด์ง„ํƒ์ƒ‰ํŠธ๋ฆฌ ๋‚ด์— ์žˆ๋Š” ๋ชจ๋“  ๊ฐ’๋“ค์„ ์ •๋ ฌ๋œ ์ˆœ์„œ๋Œ€๋กœ ํƒ์ƒ‰ ๊ฐ€๋Šฅ

3. ํ›„์œ„ ์ˆœํšŒ(Postorder Traversal)

์™ผ์ชฝ ๋…ธ๋“œ-์˜ค๋ฅธ์ชฝ ๋…ธ๋“œ-ํ˜„์žฌ ๋…ธ๋“œ ์ˆœ์œผ๋กœ ์ˆœํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•

์ˆœํšŒ ๊ฒฐ๊ณผ : G โ†’ D โ†’ E โ†’ B โ†’ F โ†’ C โ†’ A

4. ๋ ˆ๋ฒจ ์ˆœ์„œ ์ˆœํšŒ(Level Order Traversal)

๋ ˆ๋ฒจ 0(๋ฃจํŠธ ๋…ธ๋“œ)๋ถ€ํ„ฐ ๋ ˆ๋ฒจ ์ฐจ๋ก€๋กœ ๋ฐฉ๋ฌธํ•˜๋ฉฐ, ๊ฐ™์€ ๋ ˆ๋ฒจ์—์„œ๋Š” ์™ผ์ชฝ์—์„œ ์˜ค๋ฅธ์ชฝ์œผ๋กœ ๊ฐ€๋ฉฐ ์ˆœํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•

์ˆœํšŒ ๊ฒฐ๊ณผ : A โ†’ B โ†’ C โ†’ D โ†’ E โ†’ F โ†’ G

๐Ÿ“–๊ตฌํ˜„

๐Ÿ“ŽNode Class

class Node:
    def __init__(self, data):
        self.data = data
        self.left = None
        self.right = None

๐Ÿ“ŽBinary Search Tree Class

class BinarySearchTree:
    def __init__(self, root):
        self.root = root

Insert

    def insert(self, data):
        self.cur = self.root
        
        while True:
            # ์ถ”๊ฐ€ํ•  ๋…ธ๋“œ๊ฐ€ ํ˜„์žฌ ์œ„์น˜์˜ ๋…ธ๋“œ๋ณด๋‹ค ์ž‘์„ ๋•Œ(์™ผ์ชฝ ์„œ๋ธŒ ํŠธ๋ฆฌ)
            if data < self.cur.data:
                # ์™ผ์ชฝ ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์žˆ์„ ๋•Œ โ†’ ํ˜„์žฌ ์œ„์น˜ ์™ผ์ชฝ ์ž์‹ ๋…ธ๋“œ๋กœ ๋ฐ”๊พธ๊ณ  ๊ณ„์† ํƒ์ƒ‰
                if self.cur.left != None:
                    self.cur = self.cur.left
                # ์™ผ์ชฝ ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์—†์„ ๋•Œ โ†’ ํ•ด๋‹น ์œ„์น˜์— ์ถ”๊ฐ€ํ•  ๊ฐ’์„ ์—ฐ๊ฒฐ ํ›„ ํƒ์ƒ‰ ๋
                else:
                    self.cur.left = Node(data)
                    break
                
            # ์ถ”๊ฐ€ํ•  ๋…ธ๋“œ๊ฐ€ ํ˜„์žฌ ์œ„์น˜์˜ ๋…ธ๋“œ๋ณด๋‹ค ํด ๋•Œ(์˜ค๋ฅธ์ชฝ ์„œ๋ธŒ ํŠธ๋ฆฌ)
            else:
                # ์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์žˆ์„ ๋•Œ โ†’ ํ˜„์žฌ ์œ„์น˜ ์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ๋กœ ๋ฐ”๊พธ๊ณ  ๊ณ„์† ํƒ์ƒ‰
                if self.cur.right != None:
                    self.cur = self.cur.right
                else:
                    self.cur.right = Node(data)
                    break
    def search(self, data):
        self.cur = self.root
        
        while self.cur:
            # ์ฐพ๊ณ ์ž ํ•˜๋Š” ๋…ธ๋“œ ์ฐพ์€ ๊ฒฝ์šฐ
            if data == self.cur.data:
                return True
            # ์ฐพ๊ณ ์ž ํ•˜๋Š” ๋…ธ๋“œ๊ฐ€ ํ˜„์žฌ ์œ„์น˜์˜ ๋…ธ๋“œ๋ณด๋‹ค ์ž‘์„ ๋•Œ โ†’ ํ˜„์žฌ ์œ„์น˜ ์™ผ์ชฝ ์ž์‹ ๋…ธ๋“œ๋กœ ๋ฐ”๊พธ๊ณ  ๊ณ„์† ํƒ์ƒ‰
            elif data < self.cur.data:
                self.cur = self.cur.left
            # ์ฐพ๊ณ ์ž ํ•˜๋Š” ๋…ธ๋“œ์ด ํ˜„์žฌ ์œ„์น˜์˜ ๋…ธ๋“œ๋ณด๋‹ค ํด ๋•Œ โ†’ ํ˜„์žฌ ์œ„์น˜ ์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ๋กœ ๋ฐ”๊พธ๊ณ  ๊ณ„์† ํƒ์ƒ‰
            else:
                self.cur = self.cur.right
            
        # ์ฐพ๊ณ ์ž ํ•˜๋Š” ๋…ธ๋“œ ๋ชป ์ฐพ์€ ๊ฒฝ์šฐ
        return False

Remove

    def remove(self, data):
        searched = False
        self.cur = self.root
        self.parent = self.root
        
        # ์‚ญ์ œํ•˜๊ณ ์ž ํ•˜๋Š” ๋…ธ๋“œ๊ฐ€ ํŠธ๋ฆฌ ์•ˆ์— ์กด์žฌํ•˜๋Š”์ง€ ์ฒดํฌ
        while self.cur:
            if data == self.cur.data:
                searched = True
                break
            elif data < self.cur.data:
                self.parent = self.cur
                self.cur = self.cur.left
            else:
                self.parent = self.cur
                self.cur = self.cur.right
            
        # ์‚ญ์ œํ•˜๊ณ ์ž ํ•˜๋Š” ๋…ธ๋“œ ์—†์Œ
        if not searched:
            return False

1. ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ

๋ถ€๋ชจ ๋…ธ๋“œ๊ฐ€ ์‚ญ์ œํ•  ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค์ง€ ์•Š๋„๋ก ํ•จ

        # ์‚ญ์ œํ•  ๋…ธ๋“œ์˜ ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ
        if self.cur.left == self.cur.right == None:
            if data < self.parent.data:
                self.parent.left = None
            else:
                self.parent.right = None

2. ์ž์‹ ๋…ธ๋“œ๊ฐ€ 1๊ฐœ์ธ ๊ฒฝ์šฐ

๋ถ€๋ชจ ๋…ธ๋“œ๊ฐ€ ์‚ญ์ œํ•  ๋…ธ๋“œ์˜ ์ž์‹ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ํ•จ

        # ์‚ญ์ œํ•  ๋…ธ๋“œ์˜ ์ž์‹ ๋…ธ๋“œ๊ฐ€ 1๊ฐœ์ธ ๊ฒฝ์šฐ
        # ๊ทธ ๊ฒฝ์šฐ ์ค‘ ์‚ญ์ œํ•  ๋…ธ๋“œ์˜ ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์™ผ์ชฝ ์ž์‹ ๋…ธ๋“œ์ธ ๊ฒฝ์šฐ
        elif self.cur.left != None and self.cur.right == None:
            if data < self.parent.data:
                self.parent.left = self.cur.left
            else:
                self.parent.right = self.cur.left
        # ๊ทธ ๊ฒฝ์šฐ ์ค‘ ์‚ญ์ œํ•  ๋…ธ๋“œ์˜ ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ์ธ ๊ฒฝ์šฐ
        elif self.cur.left == None and self.cur.right != None:
            if data < self.parent.data:
                self.parent.left = self.cur.right
            else:
                self.parent.right = self.cur.right

3. ์ž์‹ ๋…ธ๋“œ๊ฐ€ 2๊ฐœ์ธ ๊ฒฝ์šฐ

        

Preorder Traversal

    def preorder_traversal(self, node):
        if not node:
            return
        print(node.data, end =' ')
        self.preorder_traversal(node.left)
        self.preorder_traversal(node.right)

Inorder Traversal

    def inorder_traversal(self, node):
        if not node:
            return
        self.inorder_traversal(node.left)
        print(node.data, end =' ')
        self.inorder_traversal(node.right)

postorder Traversal

    def postorder_traversal(self, node):
        if not node:
            return
        self.postorder_traversal(node.left)
        self.postorder_traversal(node.right)
        print(node.data, end =' ')

Levelorder Traversal

    def levelorder_traversal(self, root):
        q = [(root, 0)]
        l = 0
        
        while q:
            node, level = q.pop(0)
            print(node.data, end = ' ')
 
            # ๋ ˆ๋ฒจ ๋ณ„ ์ค„๋ฐ”๊ฟˆ ์ถœ๋ ฅ
            if level != l:
                l += 1
                print()
                
            if node.left:
                q.append((node.left, level + 1))
            if node.right:
                q.append((node.right, level + 1))

๐Ÿ“–์‹œ๊ฐ„๋ณต์žก๋„

h๋Š” ํŠธ๋ฆฌ์˜ ๋†’์ด

์—ฐ์‚ฐ์‹œ๊ฐ„๋ณต์žก๋„
์‚ฝ์ž…O(h)
์‚ญ์ œO(h)
ํƒ์ƒ‰O(h)
  • ์—ฐ์‚ฐ ๋ชจ๋‘ ํŠธ๋ฆฌ์˜ ๋†’์ด์— ์˜ํ•ด ์‹œ๊ฐ„๋ณต์žก๋„๊ฐ€ ๊ฒฐ์ • โ†’ ํŠธ๋ฆฌ๊ฐ€ ํ•œ ์ชฝ์œผ๋กœ ์น˜์šฐ์ณ์ง„ ๊ฒฝ์šฐ ์‹œ๊ฐ„๋ณต์žก๋„๊ฐ€ ๋„ˆ๋ฌด ์ปค์ง