๐ํธ๋ฆฌ
- 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)
๐์ฉ์ด
- 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
(์ถ์ฒ: 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๊ฐ์ผ ๋
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๊ฐ์ง ์ด๋ค. (๋ฐฉํฅ๋ง ๋ฐ๋)
- ์ญ์ ํ Node์ ์ค๋ฅธ์ชฝ child ์ค, ๊ฐ์ฅ ์์ ๊ฐ(๊ฐ์ฅ ์ผ์ชฝ ๋ ธ๋)์ ์ญ์ ํ Node์ Parent Node๊ฐ ๊ฐ๋ฆฌํค๋๋ก ํ๋ค.
- ์ญ์ ํ 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๊ฐ ์์ ๋
Case 3-2) ์ญ์ ํ๋ ค๋ ๋ ธ๋๊ฐ "์ค๋ฅธ์ชฝ"์ child node๋ฅผ ๊ฐ์ง๊ณ ์์ ๋
- Case 3-2-1) change_node์ ์ค๋ฅธ์ชฝ์ child๊ฐ ์์ ๋
- Case 3-2-2) change_node์ ์ค๋ฅธ์ชฝ์ child๊ฐ ์์ ๋
## 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)$์ด ๋๋ค.
'Algorithm > Data Structure' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Data Structure (5) Graph (๊ทธ๋ํ) (0) | 2021.05.08 |
---|---|
Data Structure - Heap (ํ) | Python ๊ตฌํ (0) | 2021.05.07 |
Data Structure (3) Hash Table (ํด์ ํ ์ด๋ธ) (0) | 2021.05.07 |
Data Structure(1) Linked List (์ฐ๊ฒฐ ๋ฆฌ์คํธ) (0) | 2021.05.07 |
๋๊ธ