binary tree structure
This commit is contained in:
parent
ba00ccad28
commit
fa387feef6
269
structure/interfaces/BinaryTree.js
Normal file
269
structure/interfaces/BinaryTree.js
Normal file
@ -0,0 +1,269 @@
|
||||
/* eslint-disable max-classes-per-file */
|
||||
|
||||
class Node {
|
||||
|
||||
constructor(data) {
|
||||
|
||||
this.info = data;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class BinaryTree {
|
||||
|
||||
/**
|
||||
* Creates an instance of BinaryTree.
|
||||
* All of the stored values will be treated as strings.
|
||||
* @memberof BinaryTree
|
||||
*/
|
||||
constructor(client, values) {
|
||||
|
||||
this.root = null;
|
||||
this.size = 0;
|
||||
this.curr = null;
|
||||
this.parent = null;
|
||||
this.client = client;
|
||||
|
||||
if (values) this.populate(values);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the tree with the values, skips duplicates
|
||||
*
|
||||
* @param {Array<any>} values
|
||||
* @return {BinaryTree}
|
||||
* @memberof BinaryTree
|
||||
*/
|
||||
populate(values) {
|
||||
|
||||
if(!(values instanceof Array)) throw new Error('Values must be an array');
|
||||
values.forEach(this.add.bind(this));
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether or not the tree is empty
|
||||
* @returns {boolean}
|
||||
* @memberof BinaryTree
|
||||
*/
|
||||
isEmpty() {
|
||||
return this.root === null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a stored value from the tree
|
||||
*
|
||||
* @param {string} val The string to search for
|
||||
* @returns {boolean} Returns true if the item is found, leaves the cursor on the found item, returns false and puts cursor to null if not found
|
||||
*/
|
||||
find(val) {
|
||||
|
||||
val.toLowerCase();
|
||||
|
||||
if(this.isEmpty()) return;
|
||||
|
||||
this.curr = this.root;
|
||||
this.parent = null;
|
||||
|
||||
while(this.curr !== null && this.curr.info !== val) {
|
||||
|
||||
if(this.compare(val, this.curr.info) > 0) {
|
||||
|
||||
this.parent = this.curr;
|
||||
this.curr = this.curr.right;
|
||||
|
||||
} else {
|
||||
|
||||
this.parent = this.curr;
|
||||
this.curr = this.curr.left;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(this.curr === null) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and retrieve the item if found.
|
||||
*
|
||||
* @param {string} val The string to search for.
|
||||
* @returns {string} If found returns the item, if not returns undefined.
|
||||
*/
|
||||
retrieveNode(val) {
|
||||
|
||||
if(this.find(val)) return this.curr.info;
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a value to the tree
|
||||
*
|
||||
* @param {string} val The value to be inserted
|
||||
*/
|
||||
add(val) {
|
||||
|
||||
if(this.find(val)) return false; //no dupes
|
||||
|
||||
this.size++;
|
||||
|
||||
const newNode = new Node(val);
|
||||
|
||||
if(this.parent === null) this.root = newNode;
|
||||
else{
|
||||
if(this.compare(val, this.parent.info) < 0) this.parent.left = newNode;
|
||||
else this.parent.right = newNode;
|
||||
this.curr = newNode;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the specified value from the tree.
|
||||
*
|
||||
* @param {string} val The value to be searched for and deleted
|
||||
*/
|
||||
remove(val) {
|
||||
|
||||
if(!this.find(val)) return;
|
||||
|
||||
this.size--;
|
||||
|
||||
if(this.curr.left === null && this.curr.right === null) {
|
||||
|
||||
if(this.parent === null) this.root = null;
|
||||
|
||||
else {
|
||||
|
||||
if(this.curr === this.parent.left) this.parent.left = null;
|
||||
else this.parent.right = null;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if(this.curr.left !== null && this.curr.right !== null) { //node has 2 children
|
||||
|
||||
let temp = this.curr;
|
||||
let replacement = this.curr.left;
|
||||
|
||||
while(replacement.right !== null) {
|
||||
|
||||
temp = replacement;
|
||||
replacement = replacement.right; //choose the right one to get the bigger value as replacement
|
||||
|
||||
}
|
||||
|
||||
this.curr.info = replacement.info;
|
||||
|
||||
if(this.curr === temp) {
|
||||
|
||||
this.curr.left = replacement.left;
|
||||
replacement = null;
|
||||
|
||||
} else {
|
||||
|
||||
temp.right = replacement.left;
|
||||
replacement = null;
|
||||
|
||||
}
|
||||
// end of 2 children
|
||||
} else { //node with 1 child
|
||||
|
||||
if(this.parent === null) { //root node
|
||||
|
||||
if(this.curr.left !== null) this.root = this.curr.left;
|
||||
else this.root = this.curr.right;
|
||||
|
||||
} else { //non-root node
|
||||
|
||||
if(this.curr === this.parent.left) { //delete left child
|
||||
|
||||
if(this.curr.right === null) this.parent.left = this.curr.left;
|
||||
else this.parent.left = this.curr.right;
|
||||
|
||||
} else { //delete right child
|
||||
|
||||
if (this.curr.right === null) this.parent.right = this.curr.left;
|
||||
else this.parent.right = this.curr.right;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}// end of node with 1 child
|
||||
|
||||
this.curr = null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares 2 strings by comparing their character codes at i.
|
||||
*
|
||||
* @param {string} val1
|
||||
* @param {string} val2
|
||||
* @returns {number} 1 if val1 is greater, -1 if val2 is greater and 0 if they are equal.
|
||||
*/
|
||||
compare(val1, val2) {
|
||||
|
||||
const len = val1.length >= val2.length ? val1.length : val2.length;
|
||||
|
||||
for(let i = 0; i < len; i++) {
|
||||
|
||||
if(val1.charCodeAt(i) === val2.charCodeAt(i)) continue;
|
||||
if(isNaN(val1.charCodeAt(i))) return -1;
|
||||
if(isNaN(val2.charCodeAt(i))) return 1;
|
||||
if(val1.charCodeAt(i) > val2.charCodeAt(i)) return 1;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
inOrder(root = this.root) {
|
||||
|
||||
if(root !== null) {
|
||||
this.inOrder(root.left);
|
||||
this.client.logger.info(root.info);
|
||||
this.inOrder(root.right);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
preOrder(root = this.root) {
|
||||
|
||||
if(root !== null) {
|
||||
this.client.logger.info(root.info);
|
||||
this.preOrder(root.left);
|
||||
this.preOrder(root.right);
|
||||
}
|
||||
}
|
||||
|
||||
postOrder(root = this.root) {
|
||||
|
||||
if(root !== null) {
|
||||
this.postOrder(root.left);
|
||||
this.postOrder(root.right);
|
||||
this.client.logger.info(root.info);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = BinaryTree;
|
Loading…
Reference in New Issue
Block a user