-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(BST): Complete BST implementation with visualization
- 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
1 parent
41ab7f9
commit b85187e
Showing
4 changed files
with
414 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
}) |
Oops, something went wrong.