티스토리 뷰
Basic/Data Structure
Tree : Binary Search Tree(BST) auto-balancing by JavaScript
Korean Eagle 2021. 8. 13. 15:56728x90
1. 자바 스크립트로 만든 간단한 BST 트리이다.
2. 필요한 대부분의 기능은 작성되어 있지만 빠진 기능이 있을 수도 있다.
3. 구현하는데 생각보다 시간이 많이 걸린다. 재귀적 사고가 많이 요구된다.
const readlineSync = require('readline-sync');
// tail -----> head
class Queue {
constructor() {
this.head = null;
this.tail = null;
this.size = 0;
}
// put data from tail
enqueue(data) {
const node = new Node(data);
if (this.isEmpty()) {
this.head = node;
this.tail = node;
} else {
this.tail.next = node;
this.tail = node;
}
this.size++;
}
// fetch data from head
dequeue() {
if (!this.isEmpty()) {
let returnNode = this.head;
if (this.size === 1) {
this.head = null;
this.tail = null;
} else {
this.head = this.head.next;
}
returnNode.next = null;
this.size--;
return returnNode.data;
}
}
isEmpty() {
return this.size === 0 ? true : false;
}
}
// [ <----
class Stack {
constructor() {
this.head = null;
this.tail = null;
this.size = 0;
}
// put data to the head
push(data) {
const node = new Node(data);
if (this.isEmpty()) {
this.head = node;
this.tail = node;
} else {
node.next = this.head;
this.head = node;
}
this.size++;
}
//fetch data from the head
pop() {
if (!this.isEmpty()) {
const returnNode = this.head;
if (this.size === 1) {
this.head = null;
this.tail = null;
} else {
this.head = this.head.next;
}
this.size--;
returnNode.next = null;
return returnNode.data;
}
}
peek() {
if (this.head !== null)
return this.head.data;
return null;
}
isEmpty() {
return this.size === 0 ? true : false;
}
}
class Node {
constructor(data) {
this.data = data;
this.next = null;
}
}
class BinaryTree {
constructor() {
this.root = null;
}
create() {
const queue = new Queue();
let input = readlineSync.question("Value of Root: ");
this.root = new TreeNode(+input);
queue.enqueue(this.root);
let cur = null;
while (!queue.isEmpty()) {
cur = queue.dequeue();
input = readlineSync.question(`Left value of ${cur.data}: `);
if (+input !== -1) {
cur.left = new TreeNode(+input);
queue.enqueue(cur.left);
}
input = readlineSync.question(`Right value of ${cur.data}: `);
if (+input !== -1) {
cur.right = new TreeNode(+input);
queue.enqueue(cur.right);
}
}
}
inorderRecursive(node) {
if (node === null) return;
this.inorderRecursive(node.left);
console.log(node.data);
this.inorderRecursive(node.right);
}
inorderIterative() {
let cur = this.root;
const stack = new Stack();
while (cur !== null || !stack.isEmpty()) {
if (cur !== null) {
stack.push(cur);
cur = cur.left;
} else {
cur = stack.pop();
console.log(cur.data);
cur = cur.right;
}
}
}
preorderRecursive(node) {
if (node === null) return;
console.log(node.data);
this.preorderRecursive(node.left);
this.preorderRecursive(node.right);
}
preorderIterative() {
let cur = this.root;
const stack = new Stack();
while (cur !== null || !stack.isEmpty()) {
if (cur !== null) {
console.log(cur.data);
stack.push(cur);
cur = cur.left;
} else {
cur = stack.pop();
cur = cur.right;
}
}
}
postorderRecursive(node) {
if (node === null) return;
this.postorderRecursive(node.left);
this.postorderRecursive(node.right);
console.log(node.data);
}
postorderIterative() {
let cur = this.root;
let node = null;
const stack = new Stack();
while (cur !== null || !stack.isEmpty()) {
if (cur !== null) {
stack.push({ cur, order: 1 });
cur = cur.left;
} else {
node = stack.pop();
cur = node.cur;
if (node.order === 1) {
stack.push({ cur, order: 2 });
cur = cur.right;
} else if (node.order === 2) {
console.log(cur.data);
// cur has to set to be null. because if the node has taken second time,
// cur is directing some node. not null
cur = null;
}
}
}
}
}
class TreeNode {
constructor(data) {
this.data = data;
this.height = 1;
this.left = null;
this.right = null;
}
}
// Binary Search Tree with Auto-balancing
// AVL Tree
class BinarySearchTree {
constructor() {
this.root = null;
}
search(node, key) {
if (node === null) return;
if (node.data === key) {
return node;
} else if (node.data > key) {
return this.search(node.left, key);
} else if (node.data < key) {
return this.search(node.right, key);
}
}
insert(node, data) {
if (node === null) {
return new TreeNode(data);
}
if (data > node.data) {
node.right = this.insert(node.right, data);
} else {
node.left = this.insert(node.left, data);
}
node.height = this.getHeighWhenCreation(node);
console.log(`Height: ${node.height} and input is ${data}`)
// *
// *
// * *
// *
// to balance Binary Search Tree, balance factor is necessary
// After the ratation, the node connected to parent has to change
if (this.getBalanceFactor(node) === 2 && node.left !== null && this.getBalanceFactor(node.left) === 1) {
node = this.LLRotation(node);
} else if (this.getBalanceFactor(node) === 2 && node.left !== null && this.getBalanceFactor(node.left) === -1) {
node = this.LRRotation(node);
} else if (this.getBalanceFactor(node) === -2 && node.right !== null && this.getBalanceFactor(node.right) === -1) {
node = this.RRRotation(node);
} else if (this.getBalanceFactor(node) === -2 && node.right !== null && this.getBalanceFactor(node.right) === 1) {
node = this.RLRotation(node);
}
return node;
}
getBalanceFactor(node) {
const leftHeight = node.left !== null ? node.left.height : 0;
const rightHeight = node.right !== null ? node.right.height : 0;
var gap = leftHeight - rightHeight
console.log(`gap : ${gap}`)
return gap;
}
LLRotation(node) {
console.log('LLR')
let p = node;
let pl = node.left;
p.left = pl.right;
pl.right = p;
// we need to recalculate the node with the balance factor with 2
p.height = this.getHeighWhenCreation(p);
pl.height = this.getHeighWhenCreation(pl)
return pl;
}
LRRotation(node) {
console.log('LRR')
let p = node;
let pl = p.left;
let plr = pl.right;
p.left = plr.right;
pl.right = plr.left;
plr.right = p;
plr.left = pl;
p.height = this.getHeighWhenCreation(p);
pl.height = this.getHeighWhenCreation(pl);
plr.height = this.getHeighWhenCreation(plr);
return plr;
}
RRRotation(node) {
console.log('RRR')
let p = node;
let pr = node.right;
p.right = pr.left;
pr.left = p;
// we need to recalculate the node with the balance factor with 2
p.height = this.getHeighWhenCreation(p);
pr.height = this.getHeighWhenCreation(pr);
return pr;
}
RLRotation(node) {
console.log('RLR')
let p = node;
let pr = p.right;
let prl = pr.left;
p.right = prl.left;
pr.left = prl.right;
prl.left = p;
prl.right = pr;
p.height = this.getHeighWhenCreation(p);
pr.height = this.getHeighWhenCreation(pr);
prl.height =this.getHeighWhenCreation(prl);
return prl;
}
// get the height from the children and plus one
getHeighWhenCreation(node) {
const leftHeight = node.left !== null ? node.left.height : 0;
const rightHeight = node.right !== null ? node.right.height : 0;
node.height = leftHeight > rightHeight ? leftHeight : rightHeight;
return node.height + 1;
}
// get the height in any position
getHeight(node) {
if (node === null) return 0;
const leftHeight = this.getHeight(node.left);
const rightHeight = this.getHeight(node.right);
return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
travsersePreorder(node) {
if (node === null) return;
console.log(node.data);
this.travsersePreorder(node.left);
this.travsersePreorder(node.right);
}
getInPost(node) {
let cur = node;
while (cur !== null && cur.left !== null) {
cur = cur.left;
}
return cur;
}
getInPre(node) {
let cur = node;
while (cur !== null && cur.right !== null) {
cur = cur.right;
}
return cur;
}
delete(node, key) {
// end conditin
if (node === null) return null;
// deletion phase
if (node.data === key && node.left === null && node.right === null) {
if (node === this.root) {
this.root = null;
}
node = null;
return null;
}
// searching phase
if (node.data > key) {
node.left = this.delete(node.left, key);
} else if (node.data < key) {
node.right = this.delete(node.right, key);
} else {
// pick up the longer side node
if (this.getHeight(node.left) > this.getHeight(node.right)) {
const pre = this.getInPre(node.left);
node.data = pre.data;
node.left = this.delete(node.left, pre.data);
} else {
const post = this.getInPost(node.right);
node.data = post.data;
node.right = this.delete(node.right, post.data);
}
}
return node;
}
// create BST only with preorder array
// myBST.createBSTWithPreorder([20, 10, 5, 15, 30, 35]);
createBSTWithPreorder(arr) {
const stack = new Stack();
// the first node is root
this.root = new TreeNode(arr[0]);
let cur = this.root;
let index = 1;
// from 1 to the last value in the array
while (index < arr.length) {
// if the new value is less than the current node,
// then make a new node to the left of current and push current node to the stack.
// and change the current position to the newly created node
// the process finished, so the index has to be increased
if (arr[index] < cur.data) {
cur.left = new TreeNode(arr[index++]);
stack.push(cur);
cur = cur.left;
}
// if the new value is larger than current node,
// then compare this node with the value of the parent node,
else {
// if the value is less than parent, then make a new node and put it to the left of current node.
// if there is no parent in stack, then it regards as infinity
// and change the position to the newly created node
// the process finished, so the index has to be increased.
const top = stack.peek();
if (top === null || arr[index] < top.data) {
cur.right = new TreeNode(arr[index++]);
cur = cur.right;
// if the value is larger than parent node,
// then pop the parent from the stack and change the position to the parent node.
// then compare the new value with the parent of the parent.
} else {
cur = stack.pop();
}
}
}
}
}
const myBST = new BinarySearchTree();
// myBST.createBSTWithPreorder([20, 10, 5, 15, 30, 35]);
// console.log(JSON.stringify(myBST));
myBST.root = myBST.insert(myBST.root, 20);
myBST.insert(myBST.root, 10);
myBST.insert(myBST.root, 30);
myBST.insert(myBST.root, 15);
myBST.insert(myBST.root, 5);
myBST.insert(myBST.root, 35);
myBST.insert(myBST.root, 3);
myBST.insert(myBST.root, 1);
myBST.insert(myBST.root, 40);
myBST.insert(myBST.root, 37);
myBST.insert(myBST.root, 7);
myBST.insert(myBST.root, 17);
myBST.insert(myBST.root, 16);
myBST.travsersePreorder(myBST.root);
console.log(JSON.stringify(myBST));
// myBST.delete(myBST.root, 6);
// myBST.delete(myBST.root, 20);
// myBST.delete(myBST.root, 30);
// myBST.delete(myBST.root, 10);
// console.log("\n\n")
// console.log(JSON.stringify(myBST));
// console.log(myBST.search(myBST.root, 11));
// console.log(myBST.getHeight(myBST.root));
// const myTree = new BinaryTree();
// myTree.create();
// console.log("--- inorder ---")
// myTree.inorderRecursive(myTree.root);
// console.log("--- preorder ---")
// myTree.preorderRecursive(myTree.root);
// console.log("--- postorder ---")
// myTree.postorderRecursive(myTree.root);
// console.log("-- inorder iterative ---")
// myTree.inorderIterative();
// console.log("-- preorder iterative ---")
// myTree.preorderIterative();
// console.log("-- postorder iterative ---")
// myTree.postorderIterative();
728x90
'Basic > Data Structure' 카테고리의 다른 글
Tree : Binary Tree creation and traversal with JavaScript (0) | 2021.05.05 |
---|
댓글
250x250
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
- 도커 개발환경 참고
- AWS ARN 구조
- Immuability에 관한 설명
- 자바스크립트 멀티 비동기 함수 호출 참고
- WSDL 참고
- SOAP 컨슈머 참고
- MySql dump 사용법
- AWS Lambda with Addon
- NFC 드라이버 linux 설치
- electron IPC
- mifare classic 강의
- go module 관련 상세한 정보
- C 메모리 찍어보기
- C++ Addon 마이그레이션
- JAX WS Header 관련 stackoverflow
- SOAP Custom Header 설정 참고
- SOAP Custom Header
- SOAP BindingProvider
- dispatcher 사용하여 설정
- vagrant kvm으로 사용하기
- git fork, pull request to the …
- vagrant libvirt bridge network
- python, js의 async, await의 차이
- go JSON struct 생성
- Netflix Kinesis 활용 분석
- docker credential problem
- private subnet에서 outbound IP 확…
- 안드로이드 coroutine
- kotlin with, apply, also 등
- 안드로이드 초기로딩이 안되는 경우
- navigation 데이터 보내기
- 레이스 컨디션 navController
- raylib