Binary Search Tree
๐ก ์ด์งย ํ์ย ํธ๋ฆฌ๋ ์ด๋ฆ์์ ์ ์ ์๋ฏ์ด, ์ฝ์ ์ด๋ ์ญ์ ๋ณด๋ค๋ ํ์์ ์ฃผ ๋ชฉ์ ์ ๋ ์๋ฃ๊ตฌ์กฐ์ด๋ค. {: .notice}
Search Tree
ํ์ ํธ๋ฆฌ
- skip lists์ hash table๋ค๊ณผ ๊ฐ๊ฑฐ๋ ๊ทธ ์ด์์ ์ฑ๋ฅ์ ๊ฐ์ง
- ์ฌ์ ์ ๊ตฌํํ๋ ๋ฐ์ ์ด์์ ์ธ ๊ตฌ์กฐ
- ์์ฐจ์ ๋๋ ๋ฑ๊ธ๋ณ ๋ฐ์ดํฐ ์ ๊ทผ์ ์ด์์
๐ก ๋น์ถ! ์ด์ง ํธ๋ฆฌ์ ์ด์ง ํ์ ํธ๋ฆฌ์ ์ฐจ์ด์
<br>
- **์ด์ง ํธ๋ฆฌ**
: ๋
ธ๋์ ์ต๋ Branch๊ฐ 2์ธ ํธ๋ฆฌ
<br>
- **์ด์ง ํ์ ํธ๋ฆฌ (Binary Search Tree, BST)**
: ์ด์ง ํธ๋ฆฌ์ ์ถ๊ฐ์ ์ธ ์กฐ๊ฑด์ด ์๋ ํธ๋ฆฌ
<br>
โ ์กฐ๊ฑด : ์ผ์ชฝ ๋
ธ๋๋ ํด๋น ๋
ธ๋๋ณด๋ค ์์ ๊ฐ, ์ค๋ฅธ์ชฝ ๋
ธ๋๋ ํด๋น ๋
ธ๋๋ณด๋ค ํฐ ๊ฐ์ ๊ฐ์ง๊ณ ์์.
{.:notice}
Binary Search Tree
์ด์ง ํ์ ํธ๋ฆฌ
์ด์ง ํ์ ํธ๋ฆฌ๋ ํธ๋ฆฌ๊ฐ ๋น์ด์์ง ์์ ๊ฒฝ์ฐ ๋ค์๊ณผ ๊ฐ์ ์์ฑ์ ๋ง์กฑํ๋ค.
-
๋ชจ๋ ๋ ธ๋ x์ ๋ํ์ฌ,
์ผ์ชฝ ์๋ธํธ๋ฆฌ์ ๋ชจ๋ key๊ฐ์ ๋ ธ๋ x์ key๊ฐ๋ณด๋ค ์๋ค.
์ค๋ฅธ์ชฝ ์๋ธํธ๋ฆฌ์ ๋ชจ๋ key๊ฐ์ ๋ ธ๋ x์ key๊ฐ๋ณด๋ค ํฌ๋ค.
- ๋ชจ๋ ๋ ธ๋๋ ์๋ก ๋ค๋ฅธ ์ ์ผํ key๊ฐ์ ๊ฐ์ง
- ์ผ์ชฝ ์๋ธ ํธ๋ฆฌ์ ์ค๋ฅธ์ชฝ ์๋ธ ํธ๋ฆฌ๋ ์ด์ง ํ์ ํธ๋ฆฌ์
- ์ด์ง ํ์ ํธ๋ฆฌ๋ฅผ ์ค์ ์ํํ๋ฉด ์ค๋ฆ์ฐจ์์ผ๋ก ์ ๋ ฌ๋ ๊ฐ์ ์ป์ ์ ์์
the class BinarySearchTree
์์ ์ด ์ํ๋จ์ ๋ฐ๋ผ ์ด์ง ํ์ ํธ๋ฆฌ์ ๋ชจ์๊ณผ ์์๋ค์ ์๊ฐ ๋ณํ๊ธฐ ๋๋ฌธ์, ์ผ๋ฐ์ ์ผ๋ก linked representation์ ์ฌ์ฉํ์ฌ ํํ๋๋ค.
Python ๊ตฌํ
ํด๋์ค ์ ์ ๋ฐ ์ด๊ธฐํclass Node(object): # ๋จผ์ ย Nodeย ํด๋์ค๋ฅผ ์ ์
def __init__(self, data):
self.data = data
self.left = self.right = None # ์ด๊ธฐํํ ๋๋ ๋ฐ์ดํฐ ๊ฐ๋ง ์ฃผ์ด์ง๊ณ ์ข์ฐ ๋
ธ๋๋ ๋น์ด์์
class BinarySearchTree(object):
def __init__(self):
self.root = None # ์ฒ์์๋ ๋น์ด ์๋ ํธ๋ฆฌ๋ก ์ด๊ธฐํ
Ascend()
๋ชจ๋ ์์๋ฅผ key์ ์ค๋ฆ์ฐจ์์ผ๋ก ์ถ๋ ฅ
Find(key)
ํ์
๋ฃจํธ๋ถํฐ ์์ํ๋ฉฐ, key๊ฐ ๋ฃจํธ๋ณด๋ค ์์ผ๋ฉด ์ผ์ชฝ ํ์ ํธ๋ฆฌ๊ฐ ํ์๋๊ณ key๊ฐ ๋ฃจํธ๋ณด๋ค ํฌ๋ฉด ์ค๋ฅธ์ชฝ ํ์ ํธ๋ฆฌ๊ฐ ํ์๋๋ค. key๊ฐ ๋ฃจํธ์ ๊ฐ์ผ๋ฉด ๊ฒ์์ด ์ฑ๊ณต์ ์ผ๋ก ์ข ๋ฃ๋๋ค.
- ๋ฃจํธ๊ฐ NULL์ด๋ฉด ํ์ ํธ๋ฆฌ๊ฐ ํธ๋ฆฌ๊ฐ ๋น์ด ์์ด ํ์ ์คํจ
- ์๊ฐ ๋ณต์ก๋ O(height)
Python ๊ตฌํ : find() Method
์ฌ๊ท์ ๊ฐ์ ๋์๊ด๊ณ ๋น๊ต๋ฅผ ํตํด ๊ตฌํํ ์ ์๋ค.class BinarySearchTree(object):
...
def find(self, key):
return self._find_value(self.root, key)
def _find_value(self, root, key):
if root is None or root.data == key:
return root is not None
elif key < root.data:
return self._find_value(root.left, key)
else:
return self._find_value(root.right, key)
Insert(key)
์ฝ์
- ์ด์ง ๊ฒ์ ํธ๋ฆฌ์ ์ ์์ e๋ฅผ ์ฝ์ ํ๋ ค๋ฉด ๋จผ์ ํธ๋ฆฌ์์ ํ์์ ์ํํ์ฌ key๊ฐ ์ด๋ฏธ ์กด์ฌํ์ง ์๋์ง ํ์ธํด์ผ ํ๋ค.
- ํ์์ด ์ฑ๊ณตํ๋ฉด ์ฝ์ ํ์ง ์์ผ๋ฉฐ, ํ์์ ์คํจํ๋ฉด ์์๊ฐ ๊ฒ์์ด ์ข ๋ฃ๋ ์ง์ ์ ์ฝ์ ๋๋ค.
๐ก ์ ๊ทธ ์ง์ ์ ์ฝ์
๋๋๊ฐ?
ํ์์ ์๋ฆฌ๋ฅผ ์ดํดํ์ผ๋ฉด ์ฝ๋ค. ํ์ ์ค ๋ฃจํธ๊ฐ NULL์ผ๋ก ํธ๋ฆฌ๊ฐ ๋น์ด์๋ ๊ฒฝ์ฐ ํ์์ ์คํจํ๊ธฐ ๋๋ฌธ{: .notice}
- ์๊ฐ ๋ณต์ก๋ O(height)
-
ex: insert key=7
Python ๊ตฌํ : Insert Method
์ฌ๊ท๋ฅผ ์ด์ฉํด์ ๊ตฌํํ๋ฉด ๊ฐ๋จํ๋ค. ์๋ก ์ถ๊ฐํ ์์์ ๊ฐ์ ํ์ฌ ๋ ธ๋์ ๊ฐ๊ณผ ๋น๊ตํ์ฌ ์ผ์ชฝ/์ค๋ฅธ์ชฝ ์ค ์๋ง์ ์์น๋ก ๋ ธ๋๋ฅผ ์ฎ๊ฒจ๊ฐ๋ฉด์ ์ฝ์ ์์น๋ฅผ ํ์ธํ๋ค.class BinarySearchTree(object): ... def insert(self, data): self.root = self._insert_value(self.root, data) return self.root is not None def _insert_value(self, node, data): if node is None: node = Node(data) else: if data <= node.data: node.left = self._insert_value(node.left, data) else: node.right = self._insert_value(node.right, data) return node
Delete(key)
์ญ์
์์์ ์ญ์ ๋ ์ธ ๊ฐ์ง ๊ฒฝ์ฐ๋ก ๋๋์ด ์๊ฐํด๋ณผ ์ ์๋ค.
- case 1 : ์์๊ฐ leaf์ ์๋ค.
-
delete key=7
-
- case 2 : ์์๊ฐ ์ฐจ์ 1์ ๋
ธ๋์ ์๋ค(์ฆ, ๋น์ด ์์ง ์์ ์๋ธํธ๋ฆฌ๊ฐ ํ๋ ์กด์ฌ).
- delete key=40
- delete key=15
- case 3 : ์์๊ฐ ์ฐจ์ 2์ ๋
ธ๋์ ์๋ค (์ฆ, ๋น์ด ์์ง ์์ ๋ ๊ฐ์ ์๋ธํธ๋ฆฌ๊ฐ ์กด์ฌ).
- ex 1) delete key=10s
| |
|:โ:|
|step 1|
| | |:โ:| |step 2. ์ผ์ชฝ ์๋ธํธ๋ฆฌ์์ ๊ฐ์ฅ ํฐ key(๋๋ ์ค๋ฅธ์ชฝ ํ์ ํธ๋ฆฌ์์ ๊ฐ์ฅ ์์ key)๋ก ๋์ฒด|
| | |:โ:| |step 3. ๊ฐ์ฅ ํฐ key๋ leaf ๋๋ ์ฐจ์ 1์ธ ๋ ธ๋์ ์์ด์ผ ํ๋ค.|
-
ex 2) delete key=20
์ผ์ชฝ ์๋ธํธ๋ฆฌ์ ๊ฐ์ฅ ํฐ key๊ฐ์ผ๋ก ๋์ฒดํ๋ค.
- ex 1) delete key=10s
| |
|:โ:|
|step 1|
- ์ผ์ชฝ ์๋ธ ํธ๋ฆฌ์์ key๊ฐ ๊ฐ์ฅ ํฐ ๋ ธ๋(+ ์ค๋ฅธ์ชฝ ์๋ธ ํธ๋ฆฌ์์ key๊ฐ ๊ฐ์ฅ ์์ ๋ ธ๋)๋ 0 ๋๋ ๋น์ด ์์ง ์์ ์๋ธ ํธ๋ฆฌ๊ฐ ํ๋ ์๋ ๋ ธ๋์ ์์ด์ผ ํฉ๋๋ค.
๐ก ๋
ธ๋์ ์ผ์ชฝ ์๋ธํธ๋ฆฌ์์ key๊ฐ ๊ฐ์ฅ ํฐ ๋
ธ๋๋ฅผ ์ฐพ๋ ๋ฐฉ๋ฒ
์๋ธ ํธ๋ฆฌ์ ๋ฃจํธ๋ก ์ด๋ํ ๋ค์ ์ค๋ฅธ์ชฝ ์์์ ํฌ์ธํฐ๊ฐ NULL์ธ ๋
ธ๋์ ๋๋ฌํ ๋๊น์ง ๊ณ์ ์ค๋ฅธ์ชฝ ์์ ํฌ์ธํฐ๋ฅผ ๋ฐ๋ผ๊ฐ๋ค.
๐ก ๋
ธ๋์ ์ค๋ฅธ์ชฝ ์๋ธํธ๋ฆฌ์์ key๊ฐ ๊ฐ์ฅ ์์ ๋
ธ๋๋ฅผ ์ฐพ๋ ๋ฐฉ๋ฒ
์๋ธ ํธ๋ฆฌ์ ๋ฃจํธ๋ก ์ด๋ํ ๋ค์ ์ผ์ชฝ ์์์ ํฌ์ธํฐ๊ฐ NULL์ธ ๋
ธ๋์ ๋๋ฌํ ๋๊น์ง ๊ณ์ ์ผ์ชฝ ์์ ํฌ์ธํฐ๋ฅผ ๋ฐ๋ผ๊ฐ๋ค.
- ์๊ฐ๋ณต์ก๋ : O(height)
Python ๊ตฌํ : delete() method
class BinarySearchTree(object):
...
def delete(self, key):
self.root, deleted = self._delete_value(self.root, key)
return deleted
def _delete_value(self, node, key):
if node is None:
return node, False
deleted = False
if key == node.data:
deleted = True
if node.left and node.right:
# replace the node to the leftmost of node.right
parent, child = node, node.right
while child.left is not None:
parent, child = child, child.left
child.left = node.left
if parent != node:
parent.left = child.right
child.right = node.right
node = child
elif node.left or node.right:
node = node.left or node.right
else:
node = None
elif key < node.data:
node.left, deleted = self._delete_value(node.left, key)
else:
node.right, deleted = self._delete_value(node.right, key)
return node, deleted
Binary Search Tree์ ์๊ฐ๋ณต์ก๋
- ์ด์ง ํธ๋ฆฌ์ ์ข์ฐ ๊ท ํ์ด ๋ง๋๋ค๋ฉด ํ์, ์ฝ์
, ์ญ์ ์ ์๊ฐ๋ณต์ก๋๊ฐย
O(log n)
-
๊ทธ๋ฌ๋ ์ด์ง ํ์ ํธ๋ฆฌ๋ ์ ๋ ฌ๋ ๋ฐ์ดํฐ์๋ ์ทจ์ฝํ๋ค.
โ ์ค๋ฆ์ฐจ์์ด๋ ๋ด๋ฆผ์ฐจ์์ด๋ ์ ๋ ฌ๋ ๋ฐ์ดํฐ๊ฐ ์ ๋ ฅ๋๋ฉด ํธํฅ ํธ๋ฆฌ(
skewed tree
)๊ฐ ์๊นโ ์ต์ ์ ๊ฒฝ์ฐ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ์ดํด์ผ ํ ์๋ ์์ด ์๊ฐ๋ณต์ก๋๊ฐย
O(n)
์ด ๋๋ค.
Indexed Binary Search Trees
-
- ๊ฐ ๋ ธ๋์๋ ์ถ๊ฐ์ ์ธ ํ๋ โLeftSizeโ๋ผ๋ ๋ณ์๊ฐ ์์
- ์ด์ง ํ์ ํธ๋ฆฌ์ ๊ธฐ๋ฅ ๋ฟ๋ง ์๋๋ผ ์์(rank)๋ณ ๊ฒ์ ๋ฐ ์ญ์ ์์ ์ด ๊ฐ๋ฅ
- LeftSize : ์ผ์ชฝ ์๋ธํธ๋ฆฌ์ ์์ ์
LeftSize์ Rank
-
์์์ rank ์ฆ, ์์๋ ์ค๋ฆ์ฐจ์ ์์์ ๋ฐ๋ฅธ ์์น๋ฅผ ๊ฐ๋ฆฌํจ๋ค.
[2, 6, 7, 8, 10, 15, 18, 20, 25, 30, 35, 40]
rank(2) = 0
rank(15) = 5
rank(20) = 7
- x๋ฅผ ๋ฃจํธ๋ ธ๋๋ก ํ๋ ์๋ธํธ๋ฆฌ์ ์์์ ๋ํ์ฌ LeftSize(x) = rank(x)
-
indexed Binary Tree์ ํ์ฉ
insert(index, element)
- ์ฌ๋ฌ ๊ฐ๋ฅ์ฑ์ด ์กด์ฌํ ์ ์๋ค.
- ๋ฃจํธ ๋ ธ๋๋ถํฐ ์๋ก์ด ๋ ธ๋๊น์ง์ leftSize๋ฅผ ์ ๋ฐ์ดํธํด์ผ ํ๋ค.
- ์๊ฐ ๋ณต์ก๋๋ O(height)
Binary Search Tree with Duplicates
์ค๋ณต์ด ์๋ ์ด์ง ํ์ ํธ๋ฆฌ
์ด์ง ํ์ ํธ๋ฆฌ์ ๋ชจ๋ ์์์ ๋ณ๋์ key๊ฐ ํ์ํ๋ค๋ ์๊ตฌ์ฌํญ์ ์ ๊ฑฐํด๋ณผ ์ ์๋ค.
For every node x,
all keys in the left subtree of x are smaller than that in x. all keys in the right subtree of x are larger than that in x
- โsmallerโ โ โsmaller or equal toโ๋ก,
- โlargerโ โ โlarger or equal toโ์ผ๋ก ๋ฐ๊พผ๋ค.
๊ทธ๋ฌ๋ฉด ์ด์ง ๊ฒ์ ํธ๋ฆฌ๊ฐ ์ค๋ณต ํค๋ฅผ ๊ฐ์ง ์ ์๊ฒ ๋๋ค.