Data Structure (2) Tree (ํŠธ๋ฆฌ)

    ๋ฐ˜์‘ํ˜•

    ๐Ÿ“ŒํŠธ๋ฆฌ

    • node์™€ branch๋ฅผ ์ด์šฉํ•ด์„œ, cycle์„ ์ด๋ฃจ์ง€ ์•Š๋„๋ก ๊ตฌ์„ฑํ•œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ
    • ํŠธ๋ฆฌ ์ค‘ binary tree(์ด์ง„ ํŠธ๋ฆฌ) ํ˜•ํƒœ์˜ ๊ตฌ์กฐ๋Š” ํƒ์ƒ‰(search) ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ตฌํ˜„์— ๋งŽ์ด ์‚ฌ์šฉ๋จ

    In computer science, a tree is a widely used abstract data type that simulates a hierarchical tree structure, with a root value and subtrees of children with a parent node, represented as a set of linked nodes.

    A tree data structure can be defined recursively as a collection of nodes (starting at a root node), where each node is a data structure consisting of a value, together with a list of references to nodes (the "children"), with the constraints that no reference is duplicated, and none points to the root.

    (์ถœ์ฒ˜: wikipedia)

    ๐Ÿ“Œ์šฉ์–ด

    img

    • node: ํŠธ๋ฆฌ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๊ธฐ๋ณธ ๋‹จ์œ„(์š”์†Œ)
    • root node: tree์˜ ๊ฐ€์žฅ ์œ„์— ์žˆ๋Š” node
    • level: ์ตœ์ƒ์œ„ ๋…ธ๋“œ๋ฅผ level 0 (๋˜๋Š” 1)ํ•˜์˜€์„ ๋•Œ, ํ•˜์œ„ branch๋กœ ์—ฐ๊ฒฐ๋œ ๋…ธ๋“œ์˜ ๊นŠ์ด
    • parent node: ์–ด๋–ค node์˜ ํ•˜์œ„ level์— ์—ฐ๊ฒฐ๋œ node
    • child node: ์–ด๋–ค ๋…ธ๋“œ์˜ ์ƒ์œ„ level์— ์—ฐ๊ฒฐ๋œ node
    • leaf node: child node๊ฐ€ ์—†๋Š” node
    • sibling (brother node): ๋™์ผํ•œ parent node๋ฅผ ๊ฐ€์ง„ ๋…ธ๋“œ
    • depth: ํŠธ๋ฆฌ์—์„œ node๊ฐ€ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ์ตœ๋Œ€ level
    • width: ํ•œ level์— ์žˆ๋Š” node์˜ ๊ฐœ์ˆ˜
    • breadth: leaf node์˜ ๊ฐœ์ˆ˜

     

    ๐Ÿ“ŒBinary Tree์™€ Binary Search Tree

    • binary tree: ํ•œ ๋…ธ๋“œ๊ฐ€ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ์ตœ๋Œ€ branch(child node)๊ฐ€ 2์ธ ํŠธ๋ฆฌ
    • binary search tree (BST): binary tree์—์„œ ์™ผ์ชฝ ๋…ธ๋“œ๋Š” ํ•ด๋‹น ๋…ธ๋“œ๋ณด๋‹ค ์ž‘์€ ๊ฐ’, ์˜ค๋ฅธ์ชฝ ๋…ธ๋“œ๋Š” ๋…ธ๋“œ๋Š” ํ•ด๋‹น ๋…ธ๋“œ๋ณด๋‹ค ํฐ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ํŠธ๋ฆฌ

     

    binary search tree์˜ ์ฃผ์š” ์šฉ๋„ / ์žฅ์ 

    • ์ฃผ์š” ์šฉ๋„๋Š” ๋ฐ์ดํ„ฐ ๊ฒ€์ƒ‰/ํƒ์ƒ‰์œผ๋กœ binary search tree๋ฅผ ์ด์šฉํ•˜๋ฉด ๊ฒ€์ƒ‰ ์†๋„์˜ ์ด์ ์ด ์žˆ๋‹ค.
    • BST vs Array

    binary-search-tree-sorted-array-animation

    (์ถœ์ฒ˜: https://blog.penjee.com/5-gifs-to-understand-binary-search-tree/#binary-search-tree-insertion-node)

     

    ๐Ÿ“ŒBST ๊ตฌํ˜„ (linked list ํ™œ์šฉ)

    Node class ๋งŒ๋“ค๊ธฐ

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

     

    Binary Search Tree์— node ์‚ฝ์ž…

    ! BST ์กฐ๊ฑด์— ๋งž๋„๋ก ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฝ์ž…ํ•ด์•ผ ํ•จ (์ž‘์€ ๊ฐ’์€ ์™ผ์ชฝ์—, ํฐ ๊ฐ’์€ ์˜ค๋ฅธ์ชฝ์—)

    class NodeMgmt:
    
      def __init__(self, head):
         self.head = head # root node
    
      def insert(self, value):
         self.current_node = self.head
         while True:
           if value < self.current_node: #์™ผ์ชฝ์œผ๋กœ ์‚ฝ์ž…
             if self.current_node.left != None: #left์— data๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ
               current_node = self.current_node.left #์žˆ์œผ๋ฉด node ์ด๋™(๋ฐ‘ ๋…ธ๋“œ ํƒ€๊ธฐ)
             else:
               current_node.left = Node(value) #left์— data ์—†์œผ๋ฉด ๋ฐ”๋กœ ์‚ฝ์ž…
             break
           else: # value > self.current_node -> ์˜ค๋ฅธ์ชฝ์œผ๋กœ ์‚ฝ์ž…
             if self.current_node.right != None: #right์— data๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ
               current_node = self.current_node.right #์žˆ์œผ๋ฉด ์•„๋ž˜ node ํƒ€๊ธฐ
             else:
               current_node.right = Node(value)
               break
    

     

    ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ ํƒ์ƒ‰ (search() ํ•จ์ˆ˜ ๊ตฌํ˜„)

    ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š”์ง€ ์—†๋Š”์ง€ ํ™•์ธํ•˜๋Š” ํ•จ์ˆ˜ (๋ง๊ทธ๋Œ€๋กœ ๊ฒ€์ƒ‰)

    def search(self, value):
         self.current_node = self.head #์ผ๋‹จ head๋ถ€ํ„ฐ search
         while self.current_node:
           if self.current_node == value:
             return True
           elif value < self.current_node:
             self.current_node = self.current_node.left
           else:
             self.current_node = self.current_node.right
         return False #์—ฌ๊ธฐ๊นŒ์ง€ ์™”๋‹ค๋Š” ๊ฑด ๋‚ด๊ฐ€ ์ฐพ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋‹ค๋Š” ๋œป
    {% endhighlight %}
    
    <br>
    
    ### <strong><span style = "color:red">์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ ์‚ญ์ œ (delete() ํ•จ์ˆ˜ ๊ตฌํ˜„)</span></strong>
    
    #### 0) ์‚ญ์ œํ•  node ํƒ์ƒ‰
    
    {% highlight python %}
      def delete(self, value):
         searched = False
         self.current_node = self.head
         self.parent = self.head #๋…ธ๋“œ ์‚ญ์ œ๋ฅผ ์œ„ํ•ด์„œ๋Š” parent node๋„ ์•Œ๊ณ  ์žˆ์œผ์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— parent๋ณ€์ˆ˜๋„ ์ƒ์„ฑํ•ด์ค€๋‹ค.
         while self.current_node:
           if self.current_node == value:
             searched = True
             break
           elif value < self.current_node:
             self.current_node = self.current_node.left
             self.parent = self.current_node
           else:
             self.current_node = self.current_node.right
             self.parent = self.current_node
    
         if searched == False:
           return False
    

    ์ด๋ ‡๊ฒŒ ์‚ญ์ œํ•  node ํƒ์ƒ‰๊นŒ์ง€ ์ง„ํ–‰ํ•˜๋ฉด self.current_node๊ฐ€ ์‚ญ์ œํ•  node๋กœ ํ• ๋‹น๋˜์–ด์žˆ๊ณ , self.parent๋Š” ์‚ญ์ œํ•  node์˜ parent node๋กœ ํ• ๋‹น๋˜์–ด ์žˆ๋Š” ์ƒํƒœ๊ฐ€ ๋œ๋‹ค.

    ์ดํ›„ ๋ถ€ํ„ฐ๋Š” ์‚ญ์ œํ•˜๋Š” case๋ฅผ ๋ถ„๋ฆฌํ•ด์„œ code๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.

     

    Case 1) ์‚ญ์ œํ•  node์˜ child node๊ฐ€ 0๊ฐœ์ผ ๋•Œ (leaf node ์‚ญ์ œ)

    ์‚ญ์ œํ•  node์˜ parent node๊ฐ€ ์‚ญ์ œํ•  node๋ฅผ ๊ฐ€๋ฆฌํ‚ค์ง€ ์•Š๋„๋ก ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋!
    node๋Š” ์‚ญ์ œํ•˜๊ณ  ์—ฐ๊ฒฐ branch๋Š” None์œผ๋กœ ์ดˆ๊ธฐํ™”

    ## case1: ์‚ญ์ œํ•  node์˜ child node๊ฐ€ 0๊ฐœ์ธ ๊ฒฝ์šฐ
         if self.current_node.left == None and self.current_node.right == None: #leaf node์ธ์ง€ ํ™•์ธ!
           if value < self.parent.value: #value๊ฐ’, current_node ์ž์ฒด๋Š” ์•Œ๊ณ  ์žˆ์ง€๋งŒ, current_node๊ฐ€ parent์˜ ์™ผ์ชฝ์— ์žˆ๋Š”์ง€, ์˜ค๋ฅธ์ชฝ์— ์žˆ๋Š”์ง€๋Š” ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค.
             self.parent.left == None
           else:
             self.parent.left == None

     

    Case 2) ์‚ญ์ œํ•  node์˜ child node๊ฐ€ 1๊ฐœ์ผ ๋•Œ

    image

    2๋ฒˆ case์—์„œ ๋˜ ๊ฒฝ์šฐ๋ฅผ ๋‚˜๋ˆ„์–ด ๋ณด๋ฉด,

    1) ์‚ญ์ œํ•˜๋ ค๋Š” ๋…ธ๋“œ๊ฐ€ "์™ผ์ชฝ"์— child node๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๋•Œ

    • ์‚ญ์ œํ•˜๋ ค๋Š” ๋…ธ๋“œ๊ฐ€ parent node์˜ ์™ผ์ชฝ์— ์žˆ์„ ๋•Œ
    • ์‚ญ์ œํ•˜๋ ค๋Š” ๋…ธ๋“œ๊ฐ€ parent node์˜ ์˜ค๋ฅธ์ชฝ์— ์žˆ์„ ๋•Œ

    2) ์‚ญ์ œํ•˜๋ ค๋Š” ๋…ธ๋“œ๊ฐ€ "์˜ค๋ฅธ์ชฝ"์— child node๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๋•Œ

    • ์‚ญ์ œํ•˜๋ ค๋Š” ๋…ธ๋“œ๊ฐ€ parent node์˜ ์™ผ์ชฝ์— ์žˆ์„ ๋•Œ
    • ์‚ญ์ œํ•˜๋ ค๋Š” ๋…ธ๋“œ๊ฐ€ parent node์˜ ์˜ค๋ฅธ์ชฝ์— ์žˆ์„ ๋•Œ
    ## case2: ์‚ญ์ œํ•  node์˜ child node๊ฐ€ 1๊ฐœ์ธ ๊ฒฝ์šฐ
         elif self.current_node.left != None and self.current_node.right == None:
           if value < self.parent.value:
             self.parent.left = self.current_node.left
           else:
             self.parent.right = self.current_node.left
    
         elif self.current_node.left == None and self.current_node.right != None:
           if value < self.parent.value:
             self.parent.left = self.current_node.right
    
           else:
             self.parent.right = self.current_node.right
    

     

    Case 3) ์‚ญ์ œํ•  node์˜ child node๊ฐ€ 2๊ฐœ์ผ ๋•Œ

    child node๊ฐ€ 2๊ฐœ์ธ ๊ฒฝ์šฐ๋Š” ๋งค์šฐ ๋ณต์žกํ•˜๋‹ค...,,ใ… _ใ… 

    ์šฐ์„ , case3์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ „๋žต์„ 2๊ฐ€์ง€ ์ด๋‹ค. (๋ฐฉํ–ฅ๋งŒ ๋ฐ˜๋Œ€)

    1. ์‚ญ์ œํ•  Node์˜ ์˜ค๋ฅธ์ชฝ child ์ค‘, ๊ฐ€์žฅ ์ž‘์€ ๊ฐ’(๊ฐ€์žฅ ์™ผ์ชฝ ๋…ธ๋“œ)์„ ์‚ญ์ œํ•  Node์˜ Parent Node๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ํ•œ๋‹ค.
    2. ์‚ญ์ œํ•  Node์˜ ์™ผ์ชฝ child ์ค‘, ๊ฐ€์žฅ ํฐ ๊ฐ’(๊ฐ€์žฅ ์˜ค๋ฅธ์ชฝ ๋…ธ๋“œ)์„ ์‚ญ์ œํ•  Node์˜ Parent Node๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ํ•œ๋‹ค.

    ๋‚˜๋Š” 1๋ฒˆ ์ „๋žต์œผ๋กœ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด๊ฒ ๋‹ค.

    ์„ธ๋ฒˆ์งธ ๊ฒฝ์šฐ์—์„œ๋„ ๋˜ ๊ฒฝ์šฐ๋ฅผ ๋‚˜๋ˆ„๋ฉด,

    Case 3-1) ์‚ญ์ œํ•˜๋ ค๋Š” ๋…ธ๋“œ๊ฐ€ "์™ผ์ชฝ"์— child node๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๋•Œ
    • Case 3-1-1) change_node์˜ ์˜ค๋ฅธ์ชฝ์— child๊ฐ€ ์žˆ์„ ๋•Œ
    • Case 3-1-2) change_node์˜ ์˜ค๋ฅธ์ชฝ์— child๊ฐ€ ์—†์„ ๋•Œ

    img

    Case 3-2) ์‚ญ์ œํ•˜๋ ค๋Š” ๋…ธ๋“œ๊ฐ€ "์˜ค๋ฅธ์ชฝ"์— child node๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๋•Œ
    • Case 3-2-1) change_node์˜ ์˜ค๋ฅธ์ชฝ์— child๊ฐ€ ์žˆ์„ ๋•Œ
    • Case 3-2-2) change_node์˜ ์˜ค๋ฅธ์ชฝ์— child๊ฐ€ ์—†์„ ๋•Œ

    img

    ## case3: ์‚ญ์ œํ•  node์˜ child node๊ฐ€ 2๊ฐœ์ธ ๊ฒฝ์šฐ
         elif self.current_node.left != None and self.current_node.right != None: # case3
           if value < self.parent.value: #์‚ญ์ œํ•˜๋ ค๋Š” ๋…ธ๋“œ๊ฐ€ "์™ผ์ชฝ"์— child node๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๋•Œ
             self.change_node = self.current_node.right
             self.change_node_parent = self.current_node.right
             while self.change_node.left != None: #์˜ค๋ฅธ์ชฝ child ์ค‘ ๊ฐ€์žฅ ์ž‘์€ ๊ฐ’ ์ฐพ๊ธฐ!(์ „๋žต1)
               self.change_node_parent = self.change_node
               self.change_node = self.change_node.left #while๋ฌธ์€ change_node๋ฅผ ์ฐพ์•„ ๊ฐ์„ ์œ„ํ•จ
             if self.change_node.right != None: #Case 3-1-1
               self.change_node_parent.left = self.change_node.right
             else: #Case 3-1-2
               self.change_node_parent.left = None
             self.parent.left = self.change_node
             self.change_node.left = self.current_node.left
             self.change_node.right = self.current_node.right
    
           else: # ์‚ญ์ œํ•˜๋ ค๋Š” ๋…ธ๋“œ๊ฐ€ "์˜ค๋ฅธ์ชฝ"์— child node๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๋•Œ
             self.change_node = self.current_node.right
             self.change_node_parent = self.current_node.right
             while self.change_node.left != None:
               self.change_node_parent = self.change_node
               self.change_node = self.change_node.left
             if self.change_node.right != None: #Case 3-2-1
               self.change_node_parent.left = self.change_node.right
             else: #Case 3-2-2
               self.change_node_parent.left = None
             self.parent.right = self.change_node
             self.change_node.left = self.current_node.left
             self.change_node.right = self.current_node.right
         return True
    

     

    test code

    # test code
    
    # 0~999์ˆซ์ž ์ค‘์—์„œ ์ž„์˜๋กœ 100๊ฐœ์˜ ์ˆซ์ž๋ฅผ ์ถ”์ถœํ•ด์„œ, ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ์— ์ž…๋ ฅ, ๊ฒ€์ƒ‰, ์‚ญ์ œ
    
    import random
    bst_nums = set() #์ง‘ํ•ฉ ๋งŒ๋“ค๊ธฐ(์ค‘๋ณต๋˜์ง€ ์•Š๋„๋ก)
    while len(bst_nums) != 100:
      bst_nums.add(random.randint(0, 999))
    
    #์„ ํƒ๋œ 100๊ฐœ์˜ ์ˆซ์ž๋ฅผ ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ์— ์ž…๋ ฅ, root node๋Š” ์ž„์˜๋กœ 500์„ ๋„˜์Œ
    head = Node(500)
    binary_tree = NodeMgmt(head)
    for num in bst_nums:
      binary_tree.insert(num)
    
    #์ž…๋ ฅํ•œ 100๊ฐœ์˜ ์ˆซ์ž search
    for num in bst_nums:
      if binary_tree.search(num) == False:
         print("search failed", num)
    
    #์ž…๋ ฅํ•œ 100๊ฐœ์˜ ์ˆซ์ž ์ค‘ 10๊ฐœ์˜ ์ˆซ์ž๋ฅผ ๋žœ๋ค ์„ ํƒํ•˜์—ฌ ์‚ญ์ œ
    delete_nums = set()
    bst_nums = list(bst_nums)
    while len(delete_nums) != 10:
      delete_nums.add(bst_nums[random.randint(0, 99)])
    for del_num in delete_nums:
      if binary_tree.delete(del_num) == False:
         print("delete failed", del_num)

    ๐Ÿ“Œ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„

    • depth๋ฅผ h๋ผ๊ณ  ํ‘œํ˜„ํ•˜๋ฉด BST์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” O(h)
    • ํŠธ๋ฆฌ๊ฐ€ n๊ฐœ์˜ node๋ฅผ ๊ฐ€์ง„๋‹ค๋ฉด h = log(n)์— ๊ฐ€๊นŒ์šฐ๋ฏ€๋กœ, ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” O(log n)์œผ๋กœ ํ‘œํ˜„ ๊ฐ€๋Šฅ

    (๋น…์˜ค ํ‘œ๊ธฐ๋ฒ•์—์„œ log n์—์„œ log์˜ ๋ฐ‘์€ 10์ด ์•„๋‹ˆ๋ผ, 2๋ฅผ ์˜๋ฏธ)

    => ์ฆ‰, ํ•œ ๋ฒˆ ์‹คํ–‰ํ•  ๋•Œ ๋งˆ๋‹ค, 50%์˜ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๋ช…๋ น์„ ์ œ๊ฑฐํ•œ๋‹ค๋Š” ์˜๋ฏธ (ํŠธ๋ฆฌ๊ฐ€ ๋ฐ˜์”ฉ ์ชผ๊ฐœ์ ธ ๊ฐ€๋ฉด์„œ depth๋Š” +1). ์ฆ‰, 50%์˜ ์‹คํ–‰์‹œ๊ฐ„์„ ๋‹จ์ถ•์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธ

    ex) ๊ท ํ˜•์ ์ธ tree์—์„œ ๋Œ€๋žต ๋…ธ๋“œ๊ฐ€ 1๊ฐœ๋ฉด depth๋Š”1, ๋…ธ๋“œ๊ฐ€ ~3๊ฐœ๋ฉด depth๋Š” 2, ๋…ธ๋“œ๊ฐ€ ~7๊ฐœ๋ฉด depth๋Š” 3, ๋…ธ๋“œ๊ฐ€ ~15๊ฐœ์ด๋ฉด depth๋Š” 4 ==> ์ฆ‰, ๋…ธ๋“œ๊ฐ€ n๊ฐœ ์ด๋ฉด depth๋Š” log n์— ์ ‘๊ทผ

     

    ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ์˜ ๋‹จ์ 

    : ์ตœ์•…์˜ ๊ฒฝ์šฐ(ํŠธ๋ฆฌ๊ฐ€ ๋น„๊ท ํ˜•์ ์ผ ๊ฒฝ์šฐ) linked list ๋“ฑ๊ณผ ๋™์ผํ•œ ์„ฑ๋Šฅ $(O(n))$์„ ๋ณด์—ฌ์คŒ

    (ํ‰๊ท  ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” $O(log n)$์ด์ง€๋งŒ, ์ด๊ฑด ํŠธ๋ฆฌ๊ฐ€ ์–‘์ชฝ์œผ๋กœ ๊ท ํ˜•์ด ์žกํ˜€์žˆ์„ ๋•Œ์˜ ์‹œ๊ฐ„๋ณต์žก๋„)

    ex) branch๊ฐ€ ํ•œ์ชฝ์œผ๋กœ๋งŒ ๋ป—์–ด์žˆ์„ ๊ฒฝ์šฐ, node๊ฐ€ n๊ฐœ ์ด๋ฉด, depth๋„ n์ด ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” $O(n)$์ด ๋œ๋‹ค.

    ๋ฐ˜์‘ํ˜•

    ๋Œ“๊ธ€