Skip to content

Commit

Permalink
feat(BST): Complete BST implementation with visualization
Browse files Browse the repository at this point in the history
- Implemented a Binary Search Tree (BST) class with essential methods:
  - `insert`: Adds a new value to the tree
  - `remove`: Deletes a specified value from the tree
  - `balance`: Balances the tree to maintain optimal structure
  - `pre-order`, `in-order`, and `post-order`: Traversal methods for various orderings
  - `findMaxHeight`: Computes the maximum height of the tree
  - `findMinHeight`: Computes the minimum height of the tree
  - `isBalanced`: Checks whether the tree is balanced
- Developed visualization to represent the tree structure and operations
  - Enhanced understanding of BST behavior and traversal methods
  • Loading branch information
MahmoodHashem committed Sep 10, 2024
1 parent 41ab7f9 commit b85187e
Show file tree
Hide file tree
Showing 4 changed files with 414 additions and 0 deletions.
48 changes: 48 additions & 0 deletions JavaScript-exercises/bst/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Binary Search Tree Visualization</title>
<link rel="stylesheet" href="./style.css">
<script defer type="module" src="js/main.js" > </script>
</head>

<body>
<h1>Binary Search Tree Visualization</h1>
<main>
<div class="inputs">
<form action="#">
<input type="number" required id="numberInput" placeholder="Enter a number" />

</form>

<button id="add">Add</button>
<button id="remove">Remove</button>
<button id="clear">Clear All</button>
<button id="balanceButton">Balance Tree</button>
<button id="inOrderButton">In-Order Traversal</button>
<button id="preOrderButton">Pre-Order Traversal</button>
<button id="postOrderButton">Post-Order Traversal</button>
<button id="postOrderButton">Level-Order Traversal</button>
<button id="isBalance">Is Balanced</button>
<button id="maxHeight">Max Height</button>
<button id="minHeight">Min Height</button>

</div>
<div class="tree">
<h2>Tree Structure:</h2>
<pre id="treeDisplay"></pre>
</div>
<div class="travers">
<h2>Traversals:</h2>
<p id="traversalDisplay"></p>
</div>
</main>



</body>

</html>
192 changes: 192 additions & 0 deletions JavaScript-exercises/bst/js/bst-logic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
class Node {
constructor(data, left = null, right = null) {
this.data = data;
this.left = left;
this.right = right;
}
}

export class BST {
constructor() {
this.root = null;
}

add(data) {
const node = this.root;
if (!node) {
this.root = new Node(data);
} else {
const searchTree = (node) => {
if (data < node.data) {
if (node.left === null) {
node.left = new Node(data);
} else {
return searchTree(node.left);
}
} else if (data > node.data) {
if (node.right === null) {
node.right = new Node(data);
} else {
return searchTree(node.right);
}
}
};
searchTree(node);
}
this.prettyPrint();
}

remove(data) {
const removeNode = function (node, data) {
if (node == null) {
return null;
}
if (data == node.data) {
// node has no children
if (node.left == null && node.right == null) {
return null;
}
// node has no left child
if (node.left == null) {
return node.right;
}
// node has no right child
if (node.right == null) {
return node.left;
}
// node has two children
var tempNode = node.right;
while (tempNode.left !== null) {
tempNode = tempNode.left;
}
node.data = tempNode.data;
node.right = removeNode(node.right, tempNode.data);
return node;
}
else if (data < node.data) {
node.left = removeNode(node.left, data);
return node;
}
else {
node.right = removeNode(node.right, data);
return node;
}
}
this.root = removeNode(this.root, data);
this.prettyPrint()
}


clearAll(){
//TODO
}


prettyPrint() {
const treeString = this._prettyPrint(this.root);
document.getElementById('treeDisplay').textContent = treeString;
}

_prettyPrint(node, prefix = "", isLeft = true) {
if (node === null) {
return "";
}
let result = "";
console.log(prefix)
if (node.right !== null) {
result += this._prettyPrint(node.right, `${prefix}${isLeft ? "│ " : " "}`, false);
}
result += `${prefix}${isLeft ? "└── " : "┌── "}${node.data}\n`;
if (node.left !== null) {
result += this._prettyPrint(node.left, `${prefix}${isLeft ? " " : "│ "}`, true);
}
return result;
}

balance() {
const sortedArray = this._inOrderTraversal(this.root);
this.root = this._sortedArrayToBST(sortedArray);
this.prettyPrint();
}

_inOrderTraversal(node, arr = []) {
if (node) {
this._inOrderTraversal(node.left, arr);
arr.push(node.data);
this._inOrderTraversal(node.right, arr);
}
return arr;
}

_sortedArrayToBST(arr) {
if (arr.length === 0) return null;
const mid = Math.floor(arr.length / 2);
const node = new Node(arr[mid]);
node.left = this._sortedArrayToBST(arr.slice(0, mid));
node.right = this._sortedArrayToBST(arr.slice(mid + 1));
return node;
}

inOrder() {
return this._inOrderTraversal(this.root).join(", ");
}

preOrder() {
return this._preOrderTraversal(this.root).join(", ");
}

postOrder() {
return this._postOrderTraversal(this.root).join(", ");
}

_levelOrder(callback) {
//TODO
}

_preOrderTraversal(node, arr = []) {
if (node) {
arr.push(node.data);
this._preOrderTraversal(node.left, arr);
this._preOrderTraversal(node.right, arr);
}
return arr;
}

_postOrderTraversal(node, arr = []) {
if (node) {
this._postOrderTraversal(node.left, arr);
this._postOrderTraversal(node.right, arr);
arr.push(node.data);
}
return arr;
}

isBalanced() {
return (this.findMinHeight() >= this.findMaxHeight() - 1)
}

findMinHeight(node = this.root) {
if (node == null) {
return -1;
};
let left = this.findMinHeight(node.left);
let right = this.findMinHeight(node.right);
if (left < right) {
return left + 1;
} else {
return right + 1;
};
}
findMaxHeight(node = this.root) {
if (node == null) {
return -1;
};
let left = this.findMaxHeight(node.left);
let right = this.findMaxHeight(node.right);
if (left > right) {
return left + 1;
} else {
return right + 1;
};
}
}
96 changes: 96 additions & 0 deletions JavaScript-exercises/bst/js/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@

import { BST } from "./bst-logic.js";



const bst = new BST();

const form = document.querySelector('form')

const addButton = document.getElementById('add');
const balanceButton = document.getElementById('balanceButton');
const isBalance = document.getElementById("isBalance")
const inOrderButton = document.getElementById('inOrderButton');
const preOrderButton = document.getElementById('preOrderButton');
const input = document.getElementById('numberInput');
const postOrderButton = document.getElementById('postOrderButton');
const remove = document.getElementById('remove');
const maxH = document.getElementById('maxHeight');
const minH = document.getElementById('minHeight');


const defaultArray = [2, 5, 3, 7, 10, 12, 25, 30, 29, 45];

addButton.addEventListener('click', () => {
const value = parseInt(input.value);
if (!isNaN(value)) {
bst.add(value);
input.value = ''; // Clear input field
} else {
alert('Please enter a valid number');
}
});

form.addEventListener('submit', () => {
event.preventDefault()
const value = parseInt(input.value);
if (!isNaN(value)) {
bst.add(value);
input.value = ''; // Clear input field
} else {
alert('Please enter a valid number');
}
})


defaultArray.forEach(value => {
bst.add(value)
})

const inOrderTra = bst.inOrder()
document.getElementById('traversalDisplay').textContent = `In-Order: ${inOrderTra}`;

remove.addEventListener('click', () => {
const value = parseInt(input.value);
bst.remove(value)
})

balanceButton.addEventListener('click', () => {
bst.balance();
});

inOrderButton.addEventListener('click', () => {
const inOrderResult = bst.inOrder();
document.getElementById('traversalDisplay').textContent = `In-Order: ${inOrderResult}`;
});

preOrderButton.addEventListener('click', () => {
const preOrderResult = bst.preOrder();
document.getElementById('traversalDisplay').textContent = `Pre-Order: ${preOrderResult}`;
});

postOrderButton.addEventListener('click', () => {
const postOrderResult = bst.postOrder();
document.getElementById('traversalDisplay').textContent = `Post-Order: ${postOrderResult}`;
});


isBalance.addEventListener('click', () => {

let balance = bst.isBalanced()

alert(balance ? "Tree is Balanced" : "Tree is NOT balanced")
});


maxH.addEventListener("click", () => {

let max = bst.findMaxHeight()

alert("Max height is " + max)
})

minH.addEventListener("click", ()=>{
let min = bst.findMinHeight();
alert("Min height is " + min);
})
Loading

0 comments on commit b85187e

Please sign in to comment.