트리 구조란 정보의 항목들이 가지로 연결될 수 있게 데이터가 조직되는 것을 말합니다. 또한, 그래프의 일종으로, 여러 노드가 한 노드를 가리킬 수 없는 구조입니다. 간단하게는 회로가 없고, 서로 다른 두 노드를 잇는 길이 하나뿐인 그래프를 트리라고 부릅니다. 계층적인 자료를 표현하는 데 이용되는 자료구조이며 노드로 이루어져 있습니다.
ex) 혈통표, 계보표
트리는 1개 이상의 노드로 이루어진 유한 집합
위 트리를 리스트로 표현한다면
(A(B(E(K,L)F),C(G),D(H(M),I,J)))
이진트리는 공백이거나 루트와 왼쪽 서브트리, 오른쪽 서브트리라고 하는 2개의 분리된 이진트리로 구성된 노드의 유한 집합
• 한 노드의 차수가 2보다 크지 않다. == 한 노드는 최대 두 개의 자식 노드를 가진다.
• 0개의 노드를 가질 수 있다. → 일반 트리에서는 0개의 노드를 가진 트리는 없으나 공백 이진 트리는 존재
• 자식의 순서를 구분한다. == 왼쪽 서브트리와 오른쪽 서브트리를 구별해야 한다.
순회 방법 : LVR, LRV, VLR, VRL, RVL, RLV
출처 : https://blog.penjee.com/5-gifs-to-understand-binary-search-tree/#binary-search-tree-insertion-node
이진탐색트리에서의 삽입, 삭제, 탐색 연산의 시간복잡도는 트리의 높이에 비례한다. 따라서, 균형잡힌 BST에서는 O(logN)의 시간복잡도를 가지지만 트리가 편향되어있다면 최악의 경우 O(N)의 시간복잡도를 가질 수 있다.
이러한 이진탐색트리의 편향문제를 해결하기 위해 AVL Tree, Red-Black Tree 등의 자료구조가 등장한다.
출처 : https://blog.penjee.com/5-gifs-to-understand-binary-search-tree/#binary-search-tree-insertion-node
public Node search(int key) {
Node temp = this.head;
while (temp != null) {
if (temp.key == key) {
return temp;
}
temp = temp.key < key ? temp.right : temp.left;
}
return null;
}
public boolean insert(Node input) {
if (this.head == null) {
this.head = input;
return true;
}
Node temp = head;
Node parent = temp.parent;
while (temp != null) {
if (input.key == temp.key)
return false;
temp = temp.key < input.key ? temp.right : temp.left;
parent = temp;
}
if (parent.key < input.key)
parent.right = input;
else
parent.left = input;
input.parent = parent;
return true;
}
public boolean delete(int key) {
Node target = search(key);
if(target == null) {
// 삭제하려는 대상이 없음
return false;
}
if(target.left == null && target.right == null) {
// 단말 노드인 경우
target = null;
return true;
}
// 오른쪽 서브트리만 존재할 때
if(target.left == null) {
if(target.parent.left == target) target.parent.left = target.right;
if(target.parent.right == target) target.parent.right = target.right;
target.right.parent = target.parent;
return true;
}
// 왼쪽 서브트리만 존재할 때
if(target.right == null) {
if(target.parent.left == target) target.parent.left = target.left;
if(target.parent.right == target) target.parent.right = target.left;
target.left.parent = target.parent;
} else {
// 양쪽 서브트리 모두 존재할 뗴
Node alternativeNode = findMinNode(target.right);
if(alternativeNode == target.right) target.right = null;
else alternativeNode.parent.left = null;
alternativeNode.left = target.left;
if(alternativeNode.left != null) alternativeNode.left.parent = alternativeNode;
alternativeNode.right = target.right;
if(alternativeNode.right != null) alternativeNode.right.parent = alternativeNode;
alternativeNode.parent = target.parent;
if(target.parent.left == target) target.parent.left = alternativeNode;
else if(target.parent.right == target) target.parent.right = alternativeNode;
target = null;
return true;
}
return false;
}
public Node findMinNode(Node target) {
while(target.left != null) target = target.left;
return target;
}
package sample;
public class BST {
private Node head;
public class Node {
Node left;
Node right;
int key;
Node parent;
}
public Node search(int key) {
Node temp = this.head;
while (temp != null) {
if (temp.key == key) {
return temp;
}
temp = temp.key < key ? temp.right : temp.left;
}
return null;
}
public boolean insert(Node input) {
if (this.head == null) {
this.head = input;
return true;
}
Node temp = head;
Node parent = temp.parent;
while (temp != null) {
if (input.key == temp.key)
return false;
temp = temp.key < input.key ? temp.right : temp.left;
parent = temp;
}
if (parent.key < input.key)
parent.right = input;
else
parent.left = input;
input.parent = parent;
return true;
}
public boolean delete(int key) {
Node target = search(key);
if(target == null) {
// 삭제하려는 대상이 없음
return false;
}
if(target.left == null && target.right == null) {
// 단말 노드인 경우
target = null;
return true;
}
// 오른쪽 서브트리만 존재할 때
if(target.left == null) {
if(target.parent.left == target) target.parent.left = target.right;
if(target.parent.right == target) target.parent.right = target.right;
target.right.parent = target.parent;
return true;
}
// 왼쪽 서브트리만 존재할 때
if(target.right == null) {
if(target.parent.left == target) target.parent.left = target.left;
if(target.parent.right == target) target.parent.right = target.left;
target.left.parent = target.parent;
} else {
// 양쪽 서브트리 모두 존재할 뗴
Node alternativeNode = findMinNode(target.right);
if(alternativeNode == target.right) target.right = null;
else alternativeNode.parent.left = null;
alternativeNode.left = target.left;
if(alternativeNode.left != null) alternativeNode.left.parent = alternativeNode;
alternativeNode.right = target.right;
if(alternativeNode.right != null) alternativeNode.right.parent = alternativeNode;
alternativeNode.parent = target.parent;
if(target.parent.left == target) target.parent.left = alternativeNode;
else if(target.parent.right == target) target.parent.right = alternativeNode;
target = null;
return true;
}
return false;
}
public Node findMinNode(Node target) {
while(target.left != null) target = target.left;
return target;
}
public static void main(String[] args) {
}
}
트리 자료구조에 대해 공부하며 기록한 글이어서 잘못된 내용이 있다면 댓글로 알려주시면 감사하겠습니다!! 😊