CS/Data Structure

[python] ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ (binary Search tree) - 4. ์‚ญ์ œ

deo2kim 2020. 9. 5. 20:33
๋ฐ˜์‘ํ˜•

๐Ÿ“— ์ด์ง„ ํŠธ๋ฆฌ (binary Search tree) - ์‚ญ์ œ

๋…ธ๋“œ ์‚ญ์ œ

๋…ธ๋“œ๋ฅผ ํ•˜๋‚˜ ์‚ญ์ œํ•ด๋ณด์ž. ๋…ธ๋“œ๋ฅผ ์‚ญ์ œํ•˜๋Š” ๊ฒฝ์šฐ๋Š” 3๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค. ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์—†์€ ๊ฒฝ์šฐ, ์ž์‹ ๋…ธ๋“œ๊ฐ€ ํ•˜๋‚˜์ธ ๊ฒฝ์šฐ, ์ž์‹๋…ธ๋“œ๊ฐ€ ๋‘˜์ธ๊ฒฝ์šฐ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋‹ค.

 

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

  • ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ๋Š” ๊ทธ๋ƒฅ ์‚ญ์ œํ•˜๋ฉด ๋œ๋‹ค.

๐Ÿ”ต ์ž์‹ ๋…ธ๋“œ๊ฐ€ ํ•˜๋‚˜์ธ ๊ฒฝ์šฐ

  • ์ž์‹ ๋…ธ๋“œ๊ฐ€ ํ•˜๋‚˜์ธ ๊ฒฝ์šฐ๋Š” ์‚ญ์ œํ•  ๋…ธ๋“œ๋ฅผ ์‚ญ์ œํ•˜๊ณ , ๊ทธ ์ž์‹ ๋…ธ๋“œ๋ฅผ ํ• ์•„๋ฒ„์ง€ ๋…ธ๋“œ์— ๋ถ™์ด๋ฉด ๋œ๋‹ค.

๐Ÿ”ต ์ž์‹ ๋…ธ๋“œ๊ฐ€ ๋‘˜์ธ ๊ฒฝ์šฐ

  • ์ž์‹ ๋…ธ๋“œ๊ฐ€ ๋‘˜์ธ ๊ฒฝ์šฐ๋Š” ์‚ญ์ œํ•  ๋…ธ๋“œ๋ฅผ ์‚ญ์ œํ•˜๊ณ , ๊ทธ ๋…ธ๋“œ์˜ ์˜ค๋ฅธ์ชฝ ์ž์‹์˜ ๊ฐ€์žฅ ์™ผ์ชฝ ์ž์†์„ ๊ฐ€์ ธ์™€์„œ ์‚ญ์ œํ•œ ๋…ธ๋“œ์˜ ๋ถ€๋ชจ ๋…ธ๋“œ์— ๋ถ™์—ฌ์ค€๋‹ค.

 

 

๐Ÿ”ต ์ „์ฒด ์ฝ”๋“œ

# ๋…ธ๋“œ ๋งŒ๋“ค๊ธฐ
#         A(val)
#        /      \
#   B(left)     C(right)
class Node:
    def __init__(self, item):
        self.val = item
        self.left = None
        self.right = None


# ์ด์ง„ํŠธ๋ฆฌ ๋งŒ๋“ค๊ธฐ
class BinaryTree:
    # ์ดˆ๊ธฐ๊ฐ’ head๋Š” None
    def __init__(self):
        self.head = Node(None)

        self.preorder_list = []
        self.inorder_list = []
        self.postorder_list = []

    # ๊ฐ’ ์ถ”๊ฐ€ํ•˜๊ธฐ head๊ฐ€ ์—†์„ ๊ฒฝ์šฐ
    def add(self, item):
        if self.head.val is None:
            self.head.val = item

        # head๊ฐ€ ์žˆ์œผ๋ฉด ์™ผ์ชฝ๋ฐฐ์น˜ or ์˜ค๋ฅธ์ชฝ๋ฐฐ์น˜
        else:
            self.__add_node(self.head, item)

    # head๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ
    def __add_node(self, cur, item):
        print('๋ถ€๋ชจ:', cur.val, '์ž์‹:', item)
        # head ๊ฐ’์ด ํฌ๋ฉด ์™ผ์ชฝ์œผ๋กœ
        if cur.val >= item:
            if cur.left is not None:
                self.__add_node(cur.left, item)
            else:
                cur.left = Node(item)
        # head ๊ฐ’์ด ์ž‘์œผ๋ฉด ์˜ค๋ฅธ์ชฝ์œผ๋กœ
        else:
            if cur.right is not None:
                self.__add_node(cur.right, item)
            else:
                cur.right = Node(item)

    # ์ฐพ๊ธฐ!!
    def search(self, item):
        if self.head.val is None:
            return False
        else:
            return self.__search_node(self.head, item)

    def __search_node(self, cur, item):
        print(cur.val, item)
        if cur.val == item:
            return True
        else:
            if cur.val >= item:
                if cur.left is not None:
                    return self.__search_node(cur.left, item)
                else:
                    return False
            else:
                if cur.right is not None:
                    return self.__search_node(cur.right, item)
                else:
                    return False

    # ์ง€์šฐ๊ธฐ!!

    def remove(self, item):
        if self.head.val == item:

            # ์ž์‹์ด ์—†์„ ๋•Œ - ๊ทธ๋ƒฅ ์ง€์šด๋‹ค
            if self.head.left == None and self.head.right == None:
                self.head.val = None

            # ์ž์‹์ด ํ•˜๋‚˜์žˆ์„ ๋•Œ - ๋ถ€๋ชจ๋ฅผ ์ง€์šฐ๊ณ  ์ž์‹์„ ํ• ์•„๋ฒ„์ง€ํ•œํ…Œ ๋ถ™์ธ๋‹ค.
            elif self.head.left == None and self.head.right != None:
                self.head = self.head.right
            elif self.head.left != None and self.head.right == None:
                self.head = self.head.left
            # ์ž์‹์ด ๋‘˜ ์žˆ์„ ๋•Œ - ์˜ค๋ฅธ์ชฝ ์ž์‹์˜ ๊ฐ€์žฅ ์™ผ์ชฝ ์ž์‹์œผ๋กœ ๋ฐ”๊ฟ”์ค€๋‹ค.
            else:
                self.head.val = self.__remove_right_and_most_left(self.head.right)

        else:
            if self.head.val > item:
                self.__remove(self.head, self.head.left, item)
            else:
                # print(self.head.val, self.head.right.val, item)
                self.__remove(self.head, self.head.right, item)

    def __remove(self, parent, cur, item):
        print(parent.val, cur.val, item)
        if cur is None:
            print('No item', item)
        if cur.val == item:
            # ์ž์‹์ด ์—†์„ ๋•Œ

            if cur.left == None and cur.right == None:
                print('์—ฌ๊ธฐ์˜ค๋„ค')
                if parent.left == cur:
                    parent.left = None
                else:
                    parent.right = None

            # ์ž์‹์ด ํ•˜๋‚˜ ์žˆ์„ ๋•Œ - ๋ถ€๋ชจ๋ฅผ ์ง€์šฐ๊ณ  ์ž์‹์„ ํ• ์•„๋ฒ„์ง€ํ•œํ…Œ ๋ถ™์ธ๋‹ค.
            elif cur.left == None and cur.right != None:
                if parent.left == cur:
                    parent.left = cur.right
                else:
                    parent.right = cur.right

            elif cur.left != None and cur.right == None:
                if parent.left == cur:
                    parent.left = cur.left
                else:
                    parent.right = cur.left

            # ์ž์‹์ด ๋‘˜ ์žˆ์„ ๋•Œ - ์˜ค๋ฅธ์ชฝ ์ž์‹์˜ ๊ฐ€์žฅ ์™ผ์ชฝ ์ž์‹์œผ๋กœ ๋ฐ”๊ฟ”์ค€๋‹ค.
            if cur.left != None and cur.right != None:
                cur.val = self.__remove_right_and_most_left(cur.right).val
                self.__removeitem(cur, cur.right, cur.val)

        else:
            if cur.val > item:
                self.__remove(cur, cur.left, item)
            else:
                self.__remove(cur, cur.right, item)


    # ์˜ค๋ฅธ์ชฝ ์ž์‹์˜ ๊ฐ€์žฅ ์™ผ์ชฝ ์ž์‹ ์ฐพ๊ธฐ
    def __remove_right_and_most_left(self, cur):
        if cur.left == None:
            return cur
        else:
            return self.__remove_right_and_most_left(cur.left)

    # ์ž์‹์ด ๋‘˜์ผ ๋•Œ ์˜ค๋ฅธ์ชฝ ์ž์‹์˜ ๊ฐ€์žฅ ์™ผ์ชฝ ์ž์‹์„ ์˜ฎ๊ธฐ๊ณ  ๊ทธ ์ž์‹์€ ์ง€์šฐ๊ธฐ
    def __removeitem(self, parent, cur, item):
        if cur.val == item:
            if parent.left == cur:
                parent.left = None
            else:
                parent.right = None
        else:
            if cur.val > item:
                self.__removeitem(cur, cur.left, item)
            else:
                self.__removeitem(cur, cur.right, item)

    # ์ˆœํšŒ Traverse
    # ์ „์œ„์ˆœํšŒ preorder 1. ๋ฃจํŠธ ๋ฐฉ๋ฌธ, 2. ์™ผ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ, 3. ์˜ค๋ฅธ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ
    # ์™„์„ฑ๋˜์–ด ์žˆ๋Š” ํŠธ๋ฆฌ๋ฅผ ๋‹ค๋ฅธ ์„œ๋ฒ„์— ๋ฆฌ์ŠคํŠธ ํ˜•ํƒœ๋กœ ๋ณด๋‚ด์„œ ๊ทธ ์„œ๋ฒ„์—์„œ ๋‹ค์‹œ ํŠธ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ•  ๋•Œ ์‚ฌ์šฉ
    def preorder_traverse(self):
        self.preorder_list = []
        if self.head is not None:
            self.__preorder(self.head)

    def __preorder(self, cur):
        self.preorder_list.append(cur.val)
        # print(cur.val)
        if cur.left is not None:
            self.__preorder(cur.left)
        if cur.right is not None:
            self.__preorder(cur.right)

    # ์ •์œ„์ˆœํšŒ inorder 1. ์™ผ์ชฝ 2. ๋ฃจํŠธ 3. ์˜ค๋ฅธ์ชฝ
    # ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌํ•  ๋•Œ | n์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋กœ ์ •๋ ฌ๊ฐ€๋Šฅ
    def inorder_traverse(self):
        self.inorder_list = []
        if self.head is not None:
            self.__inorder(self.head)

    def __inorder(self, cur):
        if cur.left is not None:
            self.__inorder(cur.left)

        self.inorder_list.append(cur.val)
        # print(cur.val)

        if cur.right is not None:
            self.__inorder(cur.right)

    # ํ›„์œ„์ˆœํšŒ postorder 1. ์™ผ์ชฝ, 3. ์˜ค๋ฅธ์ชฝ, 3. ๋ฃจํŠธ
    #
    def postorder_traverse(self):
        self.postorder_list = []
        if self.head is not None:
            self.__postorder(self.head)

    def __postorder(self, cur):
        if cur.left is not None:
            self.__postorder(cur.left)

        if cur.right is not None:
            self.__postorder(cur.right)

        self.postorder_list.append(cur.val)
        # print(cur.val)


lst = [50, 30, 24, 5, 28, 45, 98, 52, 60]
bt = BinaryTree()
for num in lst:
    bt.add(num)

print(bt.search(60))
# ์ „์šฐ
bt.preorder_traverse()
print(bt.preorder_list)
# ์ค‘์œ„
bt.inorder_traverse()
print(bt.inorder_list)
# ํ›„์œ„
bt.postorder_traverse()
print(bt.postorder_list)

bt.remove(24)
print(bt.search(60))
# ์ „์šฐ
bt.preorder_traverse()
print(bt.preorder_list)
# ์ค‘์œ„
bt.inorder_traverse()
print(bt.inorder_list)
# ํ›„์œ„
bt.postorder_traverse()
print(bt.postorder_list)

# ์ถœ์ฒ˜: https://www.youtube.com/watch?v=0CqDdXOr6Kk
๋ฐ˜์‘ํ˜•