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