트리란 고전적인 데이터 구조를 말합니다.
연결 리스트처럼 노드로 이루어졌습니다. 노드들 사이에서 부모 자식 관계를 가지며, 한개의 부모 밑에는 여러가지의 자식 노드를 가질 수 있습니다.
리스트는 하나의 라인으로 구성되어있습니다. 즉 하나의 경로 밖에 없습니다.
하지만 트리 같은 경우 선형적이지 않고, 여러개의 갈래로 나눠 질 수 있습니다. 즉 경로에 여러가지 경우의 수가 만들어 질 수 있습니다.
위의 두 그림은 트리라고 할 수 없습니다. 트리구조에는 부모 자식의 관계만 가져야합니다. 형제 관계는 없습니다. 또한 오직 하나의 루트만 가져야 한다는 것, 자식노드가 부모노드를 가르킬 수 는 없다는 것 등을 유의해야합니다.
대표적인 예는 HTML DOM 입니다.
정확하게 트리구조를 갖고 있고, 자바스크립트로 이를 동적으로 가져갈 수 있습니다.
네트워크 라우팅을 할 때도 트리구조를 이용해서 라우팅을 해주고, 추상화와 같은 다양한 분야에 트리 구조가 응용 됩니다.
트리에는 매우 다양한 종류가 있습니다. 그 중 가장 대표적인 이진 트리에 대해 알아보겠습니다.
이진 트리란 : 일반적인 트리구조에서 하나의 법칙을 추가합니다. 그 법칙은 하나의 노드가 가질수 있는 최대 자식노드가 2개라는 것 입니다.
(최대 이기 때문에 가질 수 있는 자식노드의 수는 0,1,2 3가지 경우의 수를 갖습니다)
위의 그림은 이진 검색 트리 입니다. 루트 노드가 8이죠. 이 값보다 작은 값은 왼쪽으로 큰 값은 오른쪽으로 배치를 합니다. 루트의 자식노드 3과 10에서도 마찬가지로 작은 값은 왼쪽, 큰 값을 오른쪽에 배치하면서 검색을 진행하는 구조입니다.
위의 그림에 나오는 각 노드를 수평선에 배치하면 크기에 맞게 정렬된 상태인 것을 확인할 수 있습니다. 정렬된 배열에서 사용하며, 검색 속도가 빠르다는 것이 장점입니다.
빠르다는 것입니다. 하나씩 다 확인하지 않아도 원하는 값을 찾을 수 잇죠.
class Node {
constructor(value){
this.value = value;
this.left = null;
this.right = null;
}
}
class BinarySearchTree {
constructor(){
this.root = null;
}
}
var tree = new BinarySearchTree();
tree.root = new Node(10);
tree.root.right = new Node(15);
tree.root.left = new Node(7);
tree.root.left.right = new Node(9);
이진트리에 값을 삽입하는 메소드에 대해 알아 보겠습니다.
1. root 에 있는 노드와 값을 비교합니다. 그보다 크면 오른쪽 작으면 왼쪽으로 이동합니다.
2. 1번과 마찬가지로 비교 후 그에 맞게 이동합니다.
3. 위의 과정을 더 이상 비교할 필요가 없을때 (Leaf와 비교가 마지막 비교)까지 비교합니다.
class Node {
constructor(value){
this.value = value;
this.left = null;
this.right = null;
}
}
class BinarySearchTree {
constructor(){
this.root = null;
}
insert(value){
var newNode = new Node(value);
if(this.root === null){
this.root = newNode;
return this;
}
var current = this.root;
while(true){
if(value === current.value) return undefined;
if(value < current.value){
if(current.left === null){
current.left = newNode;
return this;
}
current = current.left;
} else {
if(current.right === null){
current.right = newNode;
return this;
}
current = current.right;
}
}
}
}
// 10
// 5 13
// 2 7 11 16
var tree = new BinarySearchTree();
tree.insert(10)
tree.insert(5)
tree.insert(13)
tree.insert(11)
tree.insert(2)
tree.insert(16)
tree.insert(7)
사실 find 즉 이진트리에서 특정 값을 찾는 방식은 insertion과 매우 유사합니다.
기본적으로 같은 방식으로 값을 찾아나가기 때문입니다.
마지막 Leaf와 비교해서 없을 경우, false 를 반환하는 것이 특징 입니다.
class Node {
constructor(value){
this.value = value;
this.left = null;
this.right = null;
}
}
class BinarySearchTree {
constructor(){
this.root = null;
}
insert(value){
var newNode = new Node(value);
if(this.root === null){
this.root = newNode;
return this;
}
var current = this.root;
while(true){
if(value === current.value) return undefined;
if(value < current.value){
if(current.left === null){
current.left = newNode;
return this;
}
current = current.left;
} else {
if(current.right === null){
current.right = newNode;
return this;
}
current = current.right;
}
}
}
find(value){
if(this.root === null) return false;
var current = this.root,
found = false;
while(current && !found){
if(value < current.value){
current = current.left;
} else if(value > current.value){
current = current.right;
} else {
found = true;
}
}
if(!found) return undefined;
return current;
}
contains(value){
if(this.root === null) return false;
var current = this.root,
found = false;
while(current && !found){
if(value < current.value){
current = current.left;
} else if(value > current.value){
current = current.right;
} else {
return true;
}
}
return false;
}
}
// 10
// 5 13
// 2 7 11 16
var tree = new BinarySearchTree();
tree.insert(10)
tree.insert(5)
tree.insert(13)
tree.insert(11)
tree.insert(2)
tree.insert(16)
tree.insert(7)
Not guaranteed