
최대 자식 2개
Full, Perfect, Complete, Degenereate, Balanced
모든 자식 개수가 0 또는 2


가장 좋은 구조는 Balanced Tree
Perfect, Complete 는 무조건 Balanced이고, Full는 보장 X
cf) Balanced가 보장되는 자료구조 ⇒ AVL Tree, R/B Tree
노드를 기준으로 노드보다 작은 값이 왼쪽, 큰 값이 오른쪽으로 미리 배치되어 있음
탐색 = 이미 정렬되어 있다는 의미로 받아들이자
이미 정렬(탐색)이 되어 있으므로 (Balanced 가 항상 보장될 시) 조회, 삭제, 삽입 시 시간복잡도 O(logn)
O(logn)을 보장해주려면 AVL, R/B 작업을 해주면 됨
ex) 밸런스는 아니지만 이진 탐색 트리..
사실상 연결리스트 ⇒ O(n)

재귀함수, 전체와 부분이 똑같은 알고리즘 사용할 때
수정 없는 이유 = search 활용해서 값 변경하면 됨
ex.search(value, newValue){}
class BinarySearchTree {
root = null;
// 재귀함수 사용 => subtree에게 insert 행동 위임한다는 것
#insert(node, value){
if(node.value > value){
// 루트 노드보다 작은 값이면 왼쪽
if(node.left){
this.#insert(node.left, value);
} else {
node.left = new Node(value);
}
} else {
// 루트 노드보다 큰 값이면 오른쪽
if(node.right){
this.#insert(node.right, value);
} else {
node.right = new Node(value);
}
}
}
insert(value){
// 어떤 값을 넣으려 할 때, 일단 어디에 넣을지 모르겠다
// 그래서 왼팔, 오른팔한테 맡긴다
// 만약 왼팔 오른팔 없으면 거기다가 넣는다
if(!this.root){
this.root = new Node(value);
} else {
this.#insert(this.root, value);
}
/* 재귀 풀이 (위는 간결 ver.)
if(this.root.value > value){
// 루트 노드보다 작은 값이면 왼쪽
this.#insert(this.root.left, value);
} else {
// 루트 노드보다 큰 값이면 오른쪽
this.#insert(this.root.right, value);
} */
/* 재귀 사용 X
if(this.root.value > value){
this.root.left.insert(value);
} else {
this.root.right.insert(value);
} */
}
}
class Node {
left = null;
right = null;
constructor(value){
this.value = value;
}
}
const bst = new BinarySearchTree();
// 8. 10, 3, 1, 14, 6, 7, 4, 13

class BinarySearchTree {
root = null;
#search(node, value){
if(node.value > value){
// 더 작은 값 찾을 때
if(!node.left){
return null;
}
if(node.left.value === value){
return node.left;
}
return this.#search(node.left, value);
} else {
// 더 큰 값 찾을 떄
if(!node.right){
return null;
}
if(node.right.value === value){
return node.right;
}
return this.#search(node.right, value);
}
}
search(value){
// 어떤 값을 넣으려 할 때, 일단 어디에 있는지 모르겠다
// 그래서 왼팔, 오른팔한테 맡긴다
// 찾으면 그 노드 return, 못 찾으면 null return
if(!this.root){
// 예외 처리 중요, 초기값!초기값!초기값!
return null;
}
if(this.root.value === value){
return this.root;
}
return this.#search(this.root, value);
}
remove(value){
}
// update 없는 이유 = search 활용해서 값변경
// ex. search(value, newValue){}
}
class Node {
left = null;
right = null;
constructor(value){
this.value = value;
}
}

4가지 경우의 수
(1) leaf(양팔 다 ❌) => 제거
(2) leaf ❌ , 왼팔 없다 => 오른팔 끌어올림
(3) leaf ❌, 오른팔 없다 => 왼팔 끌어올림
(4) leaf ❌, 양팔 다 있다 => 왼팔에서 가장 큰 애와 바꾼다
📌 4번의 경우



class BinarySearchTree {
root = null;
#remove(node, value){
if(!node){
// 제거할 값이 BST에 존재하지 않을 때
return false; // 지울 값이 없으면 false return
}
if(node.value === value){ // 자식 입장
// 지울 값을 찾은 경우
if(!node.left && !node.right){ // leaf = 양팔이 없는 경우
return null;
} else if(!node.left){ // 왼팔만 없는 경우
return node.right;
} else if(!node.right){ // 오른팔만 없는 경우
return node.left;
} else { // 양팔 다 있는 경우
let exchange = node.left; // node.left.right.right.right... left 한 번 이후, 최대한 오른쪽으로 가야함
while(exchange.right){ // 가장 right값 탐색
exchange = exchange.right;
}
let temp = node.value; // 값 변경
node.value = exchange.value;
exchange.value = temp;
node.left = this.#remove(node.left, exchange.value); // 8이라는 값 제거
return node;
}
} else { // (위임한) 부모 입장, 부모의 왼팔/오른팔, 자식의 값들이 합쳐지는 것
if(node.value > value){
node.left = this.#remove(node.left, value); // 자식이 null 리턴시 잘라버린다
return node; // 대입할 값 return을 통해 update
} else {
node.right = this.#remove(node.right, value); // 자식이 null 리턴시 잘라버린다
return node; // 대입할 값 return을 통해 update
}
}
}
remove(value){
let node = this.#remove(this.root, value);
if(node){ // 값을 못 찾은 경우 대비
this.root = node; // 값을 찾은 경우에만 노드에 값 넣어주기
}
}
}
class Node {
left = null;
right = null;
constructor(value){
this.value = value;
}
}

const bst = new BinarySearchTree();
// 8. 10, 3, 1, 14, 6, 7, 4, 13
bst.insert(8);
bst.insert(10);
bst.insert(3);
bst.insert(1);
bst.insert(14);
bst.insert(6);
bst.insert(7);
bst.insert(4);
bst.insert(13);
console.log(bst.search(7)); // Node { left: null, right: null, value: 7 }
console.log(bst.search(5)); // null
bst.remove(8);

console.log(bst.remove(15));// false가 맞지만,재귀라서 root 리턴 (나중에 수정하자)
bst.remove(4);
bst;

const bst2 = new BinarySearchTree();
bst2.insert(50);
bst2.remove(50);
bst2.root; // nul

