이진 탐색 트리 (BST) 는 이진 트리(Binary Tree)의 한 종류로, 탐색을 효율적으로 수행하기 위한 규칙을 가진 트리입니다.
이 규칙 덕분에, 트리에서 탐색·삽입·삭제 연산을 평균 O(log N) 시간 내에 수행할 수 있습니다.
| 용어 | 설명 |
|---|---|
| 루트(Root) | 트리의 시작 노드 |
| 리프(Leaf) | 자식 노드가 없는 끝 노드 |
| 서브트리(Subtree) | 특정 노드를 루트로 가지는 트리 |
| 차수(Degree) | 노드가 가진 자식의 수 |
| 높이(Height) | 루트에서 리프까지의 최대 깊이 |
struct Node
{
Node* parent = nullptr;
Node* left = nullptr;
Node* right = nullptr;
int key = {};
};
parent: 부모 노드를 가리킵니다.left: 왼쪽 자식 노드를 가리킵니다.right: 오른쪽 자식 노드를 가리킵니다.key: 이 노드에 저장된 값입니다.이 구조는 BST가 재귀적으로 구성된다는 점을 그대로 반영합니다.
class BinarySearchTree
{
public:
void Print(); // 트리를 콘솔에 시각적으로 출력
void Print_Inorder(); // 중위 순회
Node* Search(Node* node, int key); // 재귀 탐색
Node* Search2(Node* node, int key); // 반복 탐색
Node* Min(Node* node); // 최소값
Node* Max(Node* node); // 최대값
Node* Next(Node* node); // 후계 노드
void Insert(int key); // 삽입
void Delete(int key); // 삭제 by key
void Delete(Node* node); // 삭제 by node
void Replace(Node* u, Node* v); // 노드 교체
private:
Node* _root = nullptr;
};
Search)Node* BinarySearchTree::Search(Node* node, int key)
{
if (node == nullptr || key == node->key)
return node;
if (key < node->key)
return Search(node->left, key);
else
return Search(node->right, key);
}
Search2)Node* BinarySearchTree::Search2(Node* node, int key)
{
while (node && key != node->key)
{
if (key < node->key)
node = node->left;
else
node = node->right;
}
return node;
}
void BinarySearchTree::Insert(int key)
{
Node* newNode = new Node();
newNode->key = key;
if (_root == nullptr)
{
_root = newNode;
return;
}
Node* node = _root;
Node* parent = nullptr;
while (node)
{
parent = node;
node = (key < node->key) ? node->left : node->right;
}
newNode->parent = parent;
if (key < parent->key)
parent->left = newNode;
else
parent->right = newNode;
}
void BinarySearchTree::Delete(int key)
{
Node* deleteNode = Search(_root, key);
Delete(deleteNode);
}
void BinarySearchTree::Delete(Node* node)
{
if (node == nullptr) return;
if (node->left == nullptr)
Replace(node, node->right);
else if (node->right == nullptr)
Replace(node, node->left);
else
{
Node* next = Next(node);
node->key = next->key;
Delete(next);
}
}
Replace)void BinarySearchTree::Replace(Node* u, Node* v)
{
if (u->parent == nullptr)
_root = v;
else if (u == u->parent->left)
u->parent->left = v;
else
u->parent->right = v;
if (v)
v->parent = u->parent;
delete u;
}
| 상황 | 처리 방식 |
|---|---|
| 자식 없음 | 바로 삭제 |
| 자식 하나 | 자식과 부모 연결만 변경 |
| 자식 둘 | 후계 노드(Next) 찾아 값 복사 후 후계 노드 삭제 |
Next)Node* BinarySearchTree::Next(Node* node)
{
if (node->right)
return Min(node->right);
Node* parent = node->parent;
while (parent && node == parent->right)
{
node = parent;
parent = parent->parent;
}
return parent;
}
오른쪽 서브트리의 가장 작은 노드 또는 조상 중 자신보다 큰 첫 노드를 반환
Node* BinarySearchTree::Min(Node* node)
{
while (node->left)
node = node->left;
return node;
}
Node* BinarySearchTree::Max(Node* node)
{
while (node->right)
node = node->right;
return node;
}
가장 왼쪽/오른쪽까지 내려가며 최솟값/최댓값을 찾습니다.
void BinarySearchTree::Print(Node* node, int x, int y)
{
if (node == nullptr) return;
SetCursorPosition(x, y);
cout << node->key;
Print(node->left, x - (5 / (y + 1)), y + 1);
Print(node->right, x + (5 / (y + 1)), y + 1);
}
void BinarySearchTree::Print_Inorder(Node* node)
{
if (node == nullptr) return;
Print_Inorder(node->left);
cout << node->key << " ";
Print_Inorder(node->right);
}
중위 순회 결과는 항상 정렬된 순서로 출력됩니다.
| 순회 방식 | 순서 | 설명 |
|---|---|---|
| 전위(Preorder) | [중] → 왼 → 오 | 루트 먼저 |
| 중위(Inorder) | 왼 → [중] → 오 | 정렬 순서 |
| 후위(Postorder) | 왼 → 오 → [중] | 자식 먼저 |
O(log N)O(N)으로 하락