A
의 Height와 Depth는 각각 3, 0
이고, I
는 0, 3
이다.다음과 같이 value와 descendants를 갖는 노드를 생성할 수 있고, descendants에 각 노드를 푸시해서 계층을 만들 수 있다.
class TreeNode {
constructor(value) {
this.value = value;
this.descendants = [];
}
}
//트리의 노드 생성하기
const A = new TreeNode('A');
const B = new TreeNode('B');
const C = new TreeNode('C');
const D = new TreeNode('D');
A.descendants.push(B,C,D);
const E = new TreeNode('E');
const F = new TreeNode('F');
B.descendants.push(E, F);
console.log(A);
A를 콘솔에 찍어보면, 다음과 같이 A.descendants
에 각각 B,C,D를 value로 가지는 노드들이 저장되어있고, B.descendants
에도 E,F를 value로 가지는 노드들이 저장되어있다.
이진트리는 가장 많이 사용되는 데이터 구조라고 할 수 있으며, 각 부모노드는 최대 2개의 자식노드와 연결되어 있어서 붙여진 이름이다. 이진트리의 유형으로는 Full
, Complete
, Perfect
등이 있다.
full binary tree
complete binary tree
perfect binary tree
이진 탐색 트리는 왼쪽 자식노드의 값이 항상 부모노드보다 작고, 오른쪽 자식노드의 값이 항상 부모노드보다 큰 이진트리이다.
(부모노드와 같은 값을 삽입할 경우, 오른쪽 자식노드의 추가하는 경우도 있는데, 이러한 중복값을 추가하는 케이스는 다음에 다루도록 하고, 이번에는 중복값은 허용하지 않는 경우로 살펴보도록 하자.)
현재 노드를 기준으로 크기를 비교한다.
현재 노드 === 삽입할 노드
리턴한다
현재 노드(A) > 삽입할 노드(X)
왼쪽 자식노드(B)의 값이 Null이라면 B에 삽입한다.B에 값이 있다면, B를 기준으로 다시 크기를 비교한다.
현재 노드(A) < 삽입할 노드(X)
오른쪽 자식노드(C)의 값이 Null이라면 C에 삽입한다. C에 값이 있다면, C를 기준으로 다시 크기를 비교한다.
값을 삭제하는 경우는 세가지가 있다.
//다음과 같은 트리가 있을때, 트리를 순회하는 방법은 다음과 같다.
10
/ \
5 30
/ / \
4 15 40
/
3
부모 -> 왼쪽 서브트리 -> 오른쪽 서브트리
10, 5, 4, 3, 30, 15, 40
왼쪽 서브트리 -> 부모 -> 오른쪽 서브트리
3, 4, 5, 10, 15, 30, 40
왼쪽 서브트리 -> 오른쪽 서브트리 -> 부모
3, 4, 5, 15, 40, 30, 10
class treeNode {
constructor(data) {
this.data = data;
this.left = null;
this.right = null;
}
}
class bst {
constructor() {
this.root = null;
}
insert(data) {
let node = new treeNode(data);
// 루드가 설정되어 있지 않다면 루트를 node로 만들어 준다. node는 treeNode()에서 뼈대를 받아온다.
if(!this.root) {
this.root = node;
return this;
}
// 비교를 위해 current 를 설정해 준다.
let current = this.root;
// current가 true 라면 while문을 돌면서 data와 지금 현재 data인 current data를 비교한다.
while (current) {
// 중복된 값은 어떤 결과를 리턴하지 않는다.
if(data === current.data) {
return;
}
// data가 기준 data(current data) 보다 작다면 왼쪽에 넣어준다.
if(data < current.data) {
if(!current.left) {
current.left = node;
break;
}
// 이제 current data(기준)는 왼쪽의 data로 잡힌다.
current = current.left;
}
// data가 기준 data(current data) 보다 크다면 오른쪽에 넣어준다.
if(data > current.data) {
if(!current.right) {
current.right = node;
break;
}
// 이제 current data(기준)는 오른쪽 data로 잡힌다.
current = current.right;
}
}
}
// BFS(너비 우선 탐색)
bfs() {
let node = this.root;
let queue = [node];
let finalData = [];
while(queue.length) {
node = queue.shift();
if(node.left) {
queue.push(node.left);
}
if(node.right) {
queue.push(node.right);
}
finalData.push(node.data);
}
return finalData;
}
// DFS(깊이 우선 탐색)
// Pre-Order traversal(전위 순회)
preOrder() {
const finalData = [];
function traverse(node) {
finalData.push(node.data);
if(node.left) {
traverse(node.left);
}
if(node.right) {
traverse(node.right);
}
}
traverse(this.root);
return finalData;
}
// In-Order traversal(중위 순회)
inOrder() {
let finalData = [];
function traverse(node) {
if(node.left) {
traverse(node.left);
finalData.push(node.data);
}
if(node.right) {
traverse(node.right);
}
}
traverse(this.root)
return finalData;
}
// Post-Order traversal(후위 순회)
postOrder() {
let finalData = [];
function traverse(node) {
if(node.left) {
traverse(node.left);
}
if(node.right) {
traverse(node.right);
finalData.push(node);
}
}
traverse(this.root)
return finalData;
}
}
reference