그래프의 일종으로 두 노드 사이의 하나의 간선만 연결되어 있는, 최소 연결과 계층 형태의 비선형 자료 구조
노드(node) : 하나 이상의 값을 갖는 객체 단위
간선(edge) : 두 노드를 연결하는 선
루트 노드(Root node) : 부모가 없는 최상위 노드
단말 노드(Leaf node) : 자식이 없는 노드
부모 노드(Parent node) : 특정 Sub-Tree 내에서의 상위 노드
자식 노드(Child node) : 특정 Sub-Tree 내에서의 하위 노드
형제(Sibling) : 부모가 없는 최상위 노드
트리 특징
트리 순회
각각의 노드가 최대 두개의 자식 노드를 가지는 트리 자료 구조
활용 방식
이진 트리의 종류
포화 이진 트리(Perfect binary Tree)
완전 이진 트리(Complete binary Tree)
정 이진 트리(Full binary Tree)
편향 이진 트리(Skewed binary Tree)
균형 이진 트리(Balanced binary Tree)
이진 트리 구현
// Node() : value와 left, right node 저장을 위한 생성자
function Node(value) {
this.value = value;
this.left = null;
this.right = null;
}
// BinaryTree() : 시작 노드인 root를 저장하기 위한 생성자
function BinaryTree() {
this.root = null;
}
// _insertNode() : 재귀로 트리를 순회하면 노드 추가 (내부 사용)
BinaryTree.prototype._insertNode = function (node, value) {
if (node === null) {
node = new Node(value);
} else if (value < node.value) {
node.left = this._insertNode(node.left, value);
} else if (value >= node.value) {
node.right = this._insertNode(node.right, value);
}
return node;
};
// insert() : 노드 추가
BinaryTree.prototype.insert = function (value) {
this.root = this._insertNode(this.root, value);
};
// _preOrderTraverseNode() : 재귀로 트리를 순회하며 전위 순회(내부 사용)
BinaryTree.prototype._preOrderTraverseNode = function (node, callback) {
if (node === null) {
return;
}
callback(node);
this._preOrderTraverseNode(node.left, callback);
this._preOrderTraverseNode(node.right, callback);
};
// preOrderTraverse() : 전위 순회하며 노드 출력
BinaryTree.prototype.preOrderTraverse = function (callback) {
this._preOrderTraverseNode(this.root, callback);
};
// _inOrderTraverseNode() : 재귀로 트리를 순회하며 중위 순회(내부 사용)
BinaryTree.prototype._inorderTraverseNode = function (node, callback) {
if (node === null) {
return;
}
this._inOrderTraverseNode(node.left, callback);
callback(node);
this._inOrderTraverseNode(node.right, callback);
};
// inOrderTraverse() : 중위 순회하며 노드 출력
BinaryTree.prototype.inOrderTraverse = function (callback) {
this._inOrderTraverseNode(this.root, callback);
};
// _postOrderTraverseNode() : 재귀로 트리를 순회하며 후위 순회(내부 사용)
BinaryTree.prototype._postOrderTraverseNode = function (node, callback) {
if (node === null) {
return;
}
this._postOrderTraverseNode(node.left, callback);
this._postOrderTraverseNode(node.right, callback);
callback(node);
};
// postOrderTraverse() : 후위 순회하며 노드 출력
BinaryTree.prototype.postOrderTraverse = function (callback) {
this._postOrderTraverseNode(this.root, callback);
};
// Queue 객체 추가
function Queue(array) {
this.array = array ? array : [];
}
Queue.prototype.isEmpty = function () {
return this.array.length == 0;
};
Queue.prototype.enqueue = function (element) {
return this.array.push(element);
};
Queue.prototype.dequeue = function () {
return this.array.shift();
};
// levelOrderTraverse() : 층별 순회하며 노드 출력
BinaryTree.prototype.levelOrderTraverse = function (callback) {
let q = new Queue();
let node;
q.enqueue(this.root);
while (!q.isEmpty()) {
node = q.dequeue();
callback(node);
if (node.left !== null) q.enqueue(node.left);
if (node.right !== null) q.enqueue(node.right);
}
};
// Node() : value와 left, right node 저장을 위한 생성자
function Node(value) {
this.value = value;
this.left = null;
this.right = null;
}
// BinarySearchTree() : 시작 노드인 root를 저장하기 위한 생성자
function BinarySearchTree() {
this.root = null;
}
// _inOrderTraverseNode() : 재귀로 트리를 순회하며 중위 순회(내부 사용)
BinarySearchTree.prototype._inorderTraverseNode = function (node, callback) {
if (node === null) {
return;
}
this._inOrderTraverseNode(node.left, callback);
callback(node);
this._inOrderTraverseNode(node.right, callback);
};
// inOrderTraverse() : 중위 순회하며 노드 출력
BinarySearchTree.prototype.inOrderTraverse = function (callback) {
this._inOrderTraverseNode(this.root, callback);
};
// _insertNode() : 재귀로 트리를 순회하면 노드 추가 (내부 사용)
BinarySearchTree.prototype._insertNode = function (node, value) {
if (node === null) {
node = new Node(value);
} else if (value < node.value) {
node.left = this._insertNode(node.left, value);
} else if (value >= node.value) {
node.right = this._insertNode(node.right, value);
}
return node;
};
// insert() : 노드 추가
BinarySearchTree.prototype.insert = function (value) {
this.root = this._insertNode(this.root, value);
};
// _minNode() : 반복문으로 트리를 순회하며 최솟값 노드 탐색
BinarySearchTree.prototype._minNode = function (node) {
if (node === null) {
return null;
}
while (node && node.left !== null) {
node = node.left;
}
return node.value;
};
// _maxNode() : 반복문으로 트리를 순회하며 최댓값 노드 탐색
BinarySearchTree.prototype._maxNode = function (node) {
if (node === null) {
return null;
}
while (node && node.right !== null) {
node = node.right;
}
return node.value;
};
// min() : 최솟값 노드 탐색
BinarySearchTree.prototype.min = function () {
return this._minNode(this.root);
};
// max() : 최댓값 노드 탐색
BinarySearchTree.prototype.max = function () {
return this._maxNode(this.root);
};
// _searchNode() : 재귀로 트리를 순회하며 값을 만족하는 노드 탐색
BinarySearchTree.prototype._searchNode = function (node, value) {
if (node === null) {
return false;
}
if (node.value === value) {
return true;
} else if (node.value > value) {
return this._searchNode(node.left, value);
} else if (node.value < value) {
return this._searchNode(node.right, value);
}
};
// search() : value 노드 탐색
BinarySearchTree.prototype.search = function (value) {
return this._searchNode(this.root, value);
};
// _finMinNode() : 반복문으로 트리를 순회하며 최솟값을 보유한 노드 탐색
BinarySearchTree.prototype._findMinNode = function (node) {
while (node && node.left !== null)
node = node.left;
return node;
};
// _removeNode() : 재귀로 트리를 순회하며 값을 만족하는 노드를 찾고 삭제
BinarySearchTree.prototype._removeNode = function (node, value) {
if (node === null)
return null;
if (node.value === value) {
// case 1 : leaf node
if (node.left === null && node.right === null) {
node = null;
}
// case 2 : 1 child node
else if (node.left === null) {
node = node.right;
} else if (node.right === null) {
node = node.left;
}
// case 3 : 2 child node
else {
let aux = this._findMinNode(node.right);
node.value = aux.value;
node.right = this._removeNode(node.right, aux.value);
}
} else if (node.value > value) {
node.left = this._removeNode(node.left, value);
} else if (node.value < value) {
node.right = this._removeNode(node.right, value);
}
return node;
};
// remove() : 노드 삭제
BinarySearchTree.prototype.remove = function (value) {
root = this._removeNode(this.root, value);
};