들어가며
- 이진 탐색 트리(Binary Search Tree, BST)는 중복된 데이터를 허용하지 않으며, 데이터가 트리에 삽입될 때 특정한 조건을 따라 저장되는 이진 트리를 말한다.
- 기존의 이진 트리에서 데이터를 탐색할 때 해당 데이터가 트리의 어느 부분에 존재하는지 알 수 없으므로 모든 노드를 탐색해야하는 문제가 있다.
- 이진 탐색 트리는 해당 문제를 해결하기 위해 고안된 자료구조로, 데이터가 삽입될 때 해당 원소와 현재 노드가 가지고 있는 원소를 비교하여 크다면 우측, 작다면 좌측으로 내려가며 저장되는 구조로 되어있다.
- 이는 데이터를 삽입, 삭제할 때 마다 자동적으로 정렬이 수행되는 구조이며 실제로 중위 순회를 BST에 수행할 시 오름차순으로 이루어진 데이터를 얻을 수 있다.
- 이렇게 데이터의 입 출력을 수행할 때마다 데이터가 자동적으로 정렬되어 있는 자료구조를 associative container라고도 부른다.
- 이진 탐색 트리를 사용하여 데이터를 탐색할 시에 값을 비교할 때 마다 탐색 범위가 절반씩 줄어드므로 특정한 상황이 아니라면 평균적으로 O(logN)이 걸린다.
이진 탐색 트리의 구현
- 이진 탐색 트리의 구현은 연결 리스트를 통하여 수행하며 아래와 같은 연산을 구현할 것이다.
- 데이터의 삽입
- 데이터의 삭제
- 데이터의 존재 유무
- 해당 이진 탐색 트리의 순회(traversal) - 해당 순회는 중위 순회(in-order traversal)로 구현할 것이다.
- 노드의 구조와 우리가 구현할 이진 탐색 트리의 전체적인 구조는 다음과 같다.
class Node{
int data;
Node left;
Node right;
Node(int data){
this.data = data;
this.left = null;
this.right = null;
}
}
class BinarySearchTree{
Node root;
BinarySearchTree(){
this.root = null;
}
public void addNode(int key){
}
public boolean searchNode(int key){
}
public void removeNode(int key){
}
public void traversal(Node cur){
if (cur == null){
return;
}
traversal(cur.left);
System.out.print(cur.data + " ");
traversal(cur.right);
}
}
- 순회의 경우 이전에 이미 구현한 적이 있으므로 여기서는 이미 구현되어 있다고 가정한다.
데이터의 삽입
- 데이터의 삽입은 이진 탐색 트리의 원리인 대소 비교를 통해 삽입할 위치를 찾는 것에서 부터 시작된다.
- 루트부터 시작해 삽입할 데이터의 값과 트리에 존재하는 값을 비교한다.
- 이때 삽입할 데이터의 값 < 현재 위치의 데이터 값 이라면 삽입할 위치는 현재 위치에서 좌측으로 이동한다.
- 삽입할 데이터의 값 > 현재 위치의 데이터 값 이라면 삽입할 위치는 현재 위치에서 우측으로 이동한다.
- 이후 이동한 위치가 null로 비어있는 공간이라면 새로운 노드를 만들어 달아주면 종료된다.
- 간단한 그림으로 예시를 들면 아래와 같은 상황이 있다고 가정하자.
- 이 경우, 8은 우선 root인 10와 대소비교를 수행한다. 8 < 10이기 때문에 원소가 삽입될 장소는 10의 좌측인 5로 이동하게 된다.
- 이후 8은 삽입될 장소를 가리키는 cur에 저장된 5와 대소비교를 수행한다. 8 > 5 이기 때문에 cur은 5의 우측으로 이동하게 된다.
- 이때 cur는 null을 가리킨다. 그림에서 보듯이 5의 우측 자식은 null로 존재하지 않기 때문이다.
- 따라서 이 장소는 8을 저장하는데 적합해 보인다. 하지만 링크를 잇는데 cur로는 부족하다. 이전 위치를 기억해야하는 포인터가 하나 더 필요하다.
- 이를 위해 pre가 존재한다. pre는 cur의 직전 노드를 가리키기 때문에 pre.right = new Node(key)라는 구문으로 링크를 이으면서 새로운 노드를 만들어 붙일 수 있다.
- 해당 과정을 코드로 옮기면 아래와 같다.
public void addNode(int key){
if (root == null){
root = new Node(key);
return;
}
if (searchNode(key)){
return;
}
Node cur = this.root;
while (true){
Node pre = cur;
if (cur.data < key){
cur = cur.right;
if (cur == null){
pre.right = new Node(key);
break;
}
} else{
cur = cur.left;
if (cur == null){
pre.left = new Node(key);
break;
}
}
}
}
- searchNode(key)는 해당 노드가 이미 트리에 존재하는지를 확인하는데 사용한다. 이전에도 서술했지만 BST는 중복된 데이터를 허용하지 않는다.
정리
- 이번에는 원소의 삽입을 알아보았다. 다음에는 원소의 삭제에 대해 구현해 볼 것이다 원소의 삭제는 삽입보다 더 까다롭다. 그리고 노드가 존재하는지 탐색하는 searchNode 역시 다음 시간에 구현해 볼 것이다.
'DataStructure > Tree' 카테고리의 다른 글
AVL트리의 원리와 구현 (1) (0) | 2023.02.27 |
---|---|
이진 탐색 트리의 원리와 구현 - (2) (0) | 2023.02.26 |
이진 트리의 구현 - (2) (0) | 2023.02.24 |
이진 트리의 구현 - (1) (0) | 2023.02.24 |
트리의 개념과 용어정리 (0) | 2023.02.23 |