Repository: CoffeelessProgrammer/Data-Structures-and-Algorithms-TS
Branch: master
Commit: 9eb4902adfab
Files: 60
Total size: 120.8 KB
Directory structure:
gitextract_i53d2ydn/
├── .gitignore
├── Algorithms/
│ ├── DynamicProgramming/
│ │ ├── Basics.ts
│ │ ├── Fibonacci.ts
│ │ └── Knapsack.ts
│ ├── README.md
│ ├── Recursion/
│ │ ├── Basics.ts
│ │ ├── Factorial.ts
│ │ └── Fibonacci.ts
│ ├── Searching/
│ │ ├── Basics.ts
│ │ ├── BreadthFirstTraversal.ts
│ │ ├── DepthFirstTraversals.ts
│ │ └── Exercise_BFSDFSUseCases.md
│ └── Sorting/
│ ├── Basics.ts
│ ├── BubbleSort.ts
│ ├── Data/
│ │ └── PlantFamilies.ts
│ ├── Exercise_SortingUseCases.md
│ ├── InsertionSort.ts
│ ├── MergeSort.ts
│ ├── QuickSort.ts
│ └── SelectionSort.ts
├── Big-O/
│ ├── Ex1.ts
│ ├── Ex2.ts
│ ├── Hello_Big_O.ts
│ ├── README.md
│ ├── Rule3.ts
│ └── n_squared.ts
├── Data-Structures/
│ ├── Arrays/
│ │ ├── Basics.ts
│ │ └── MyArray.ts
│ ├── Graphs/
│ │ └── SimpleGraph.ts
│ ├── Hash-Tables/
│ │ └── HashTable.ts
│ ├── Linked-Lists/
│ │ ├── DoublyLinkedList.ts
│ │ ├── DoublyNode.ts
│ │ ├── LinkedList.ts
│ │ └── SinglyNode.ts
│ ├── README.md
│ ├── Sequential/
│ │ ├── Queue.ts
│ │ ├── Stack.ts
│ │ └── StackLL.ts
│ └── Trees/
│ ├── BinarySearchTree.test.ts
│ ├── BinarySearchTree.ts
│ └── BinaryTreeNode.ts
├── Playground/
│ ├── Demos/
│ │ ├── Classes_101.ts
│ │ └── Objects_101.ts
│ ├── Interviews/
│ │ └── HealthcareHM.ts
│ ├── Puzzles/
│ │ ├── AngryFrogs.test.ts
│ │ └── AngryFrogs.ts
│ └── ZTM Challenges/
│ ├── Arrays/
│ │ ├── Compare_Arrays.test.ts
│ │ ├── Compare_Arrays.ts
│ │ ├── Merge_Sorted_Arrays.ts
│ │ ├── Reverse_String.ts
│ │ └── Sum_Pair.ts
│ ├── Hash-Tables/
│ │ ├── Recurring_Symbol.test.ts
│ │ └── Recurring_Symbol.ts
│ ├── Josephus.ts
│ ├── Recursion/
│ │ └── ReverseString.ts
│ ├── StackifiedQueue.ts
│ └── ValidatorBST.ts
├── README.md
├── deps.ts
└── test_deps.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
deno_dir
================================================
FILE: Algorithms/DynamicProgramming/Basics.ts
================================================
// ----------------------- Class Implementation -----------------------
class MemoizationExample {
private static cache = Object.create({});
public static resetCache() {
this.cache = null;
this.cache = Object.create({});
}
public static memoizedAddTo42(n: number, visualize?: boolean): number {
if (n in this.cache) {
if (visualize) console.log('Found!', n, '+ 42 =', this.cache[n]);
return this.cache[n];
} else {
if (visualize) console.log('New encounter!', n);
this.cache[n] = n + 42;
return this.cache[n]
}
}
public static addTo42(n: number): number {
console.log('Long time!', n);
return n + 42;
}
}
// ----------------------- Closure Implementation -----------------------
function memoizedAddTo64() {
let cache = Object.create({});
return function(n: number): number {
if (n in cache) {
console.log('Found!', n, '+ 64 =', cache[n]);
return cache[n];
} else {
console.log('New encounter!', n);
cache[n] = n + 64;
return cache[n]
}
}
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
console.log('------------ Memoization via Class ------------');
MemoizationExample.memoizedAddTo42(17, true);
MemoizationExample.memoizedAddTo42(15, true);
MemoizationExample.memoizedAddTo42(17, true);
MemoizationExample.memoizedAddTo42(28, true);
MemoizationExample.memoizedAddTo42(28, true);
console.log('\n----------- Memoization via Closure -----------');
const memoized = memoizedAddTo64();
memoized(7);
memoized(5);
memoized(5);
// RUN: deno run Algorithms/DynamicProgramming/Basics.ts
}
// --------------------------- Terminal Output: ---------------------------
// ------------ Memoization via Class ------------
// New encounter! 17
// New encounter! 15
// Found! 17 + 42 = 59
// New encounter! 28
// Found! 28 + 42 = 70
// ----------- Memoization via Closure -----------
// New encounter! 7
// New encounter! 5
// Found! 5 + 64 = 69
================================================
FILE: Algorithms/DynamicProgramming/Fibonacci.ts
================================================
// ---------------- Fibonacci Sequence ----------------
// 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144...
class FibonacciMemoized {
private static cache = Object.create({});
private static _initialize = (() => {
FibonacciMemoized.cache[1] = 0;
FibonacciMemoized.cache[2] = 1;
})();
public static nthTerm(nth: number): number {
if (nth in this.cache)
return this.cache[nth];
else
this.cache[nth] = this.nthTerm(nth-2) + this.nthTerm(nth-1);
return this.cache[nth];
}
}
function fibonacciBottomUp() {
let fibonacciSequence: number[] = [0,1];
return function(nth: number): number | undefined {
if (nth < 1) return undefined;
else nth = Math.floor(nth);
for (let i=fibonacciSequence.length; i <= nth; ++i)
fibonacciSequence.push(fibonacciSequence[i-2]+ fibonacciSequence[i-1]);
return fibonacciSequence[nth-1];
}
}
function executionTime(n: number): string {
const t0 = performance.now();
console.log('Term', n+':', FibonacciMemoized.nthTerm(n));
const t1 = performance.now();
return (t1-t0) + 'ms';
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
console.log('\n------------ Memoization ------------');
const a1 = Object.create({});
a1.run_1 = executionTime(256);
a1.run_2 = executionTime(256);
a1.run_3 = executionTime(16);
a1.run_4 = executionTime(8);
console.table(a1);
console.log('\n------------ Bottom Up ------------');
const fibBot = fibonacciBottomUp();
console.log('Term 1:', fibBot(1));
console.log('Term 6:', fibBot(6));
console.log('Term 11:', fibBot(11));
console.log('Term 42:', fibBot(42));
// RUN: deno run Algorithms/DynamicProgramming/Fibonacci.ts
}
// --------------------------- Terminal Output: ---------------------------
//
// ------------ Memoization ------------
// Term 256: 8.757159534301882e+52
// Term 256: 8.757159534301882e+52
// Term 16: 610
// Term 8: 13
// ┌───────┬────────┐
// │ (idx) │ Values │
// ├───────┼────────┤
// │ run_1 │ "2ms" │
// │ run_2 │ "8ms" │
// │ run_3 │ "2ms" │
// │ run_4 │ "12ms" │
// └───────┴────────┘
//
// ------------ Bottom Up ------------
// Term 1: 0
// Term 6: 5
// Term 11: 55
// Term 42: 165580141
================================================
FILE: Algorithms/DynamicProgramming/Knapsack.ts
================================================
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
// RUN: deno run Algorithms/DynamicProgramming/Knapsack.ts
}
================================================
FILE: Algorithms/README.md
================================================
# Algorithms
## Core
- [X] Recursion
- [X] Dynamic Programming
- [X] Comparison Sorting
- [X] *Merge Sort*
- [X] *Quicksort*
- [X] Bubble Sort
- [X] Selection Sort
- [X] Insertion Sort
- [X] Searching
- [X] Linear Search
- [ ] Binary Search
- [X] Breadth First Search (BFS)
- [X] Depth First Search (DFS)
## Resources
- [Visualizing Data Structures & Algorithms](https://visualgo.net/en)
- [Unicode Characters | RapidTables](https://www.rapidtables.com/code/text/unicode-characters.html)
- [The Big-O Algorithm Complexity Cheat Sheet](https://www.bigocheatsheet.com/ "Big O Cheat Sheet")
### Dynamic Programming
- [Closures | JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures)
### Recursion
- [Recursion | Brilliant.org](https://brilliant.org/wiki/recursion-problem-solving/)
- [Tail Call Optimization in ES6](https://2ality.com/2015/06/tail-call-optimization.html)
### Searching
- [Graph Traversals | VisuAlgo](https://visualgo.net/en/dfsbfs)
- [Tree Traversals: Preorder, Inorder, & Postorder](https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/)
- [Space Complexity: BFS vs DFS](https://stackoverflow.com/questions/9844193/what-is-the-time-and-space-complexity-of-a-breadth-first-and-depth-first-tree-tr)
### Sorting
- [Array.prototype.sort()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)
- [Animated Sorting | Toptal](https://www.toptal.com/developers/sorting-algorithms)
- [Dancing Algorithms | AlgoRythmics](https://www.youtube.com/user/AlgoRythmics/videos)
- [QuickSort vs Heapsort](https://stackoverflow.com/questions/2467751/quicksort-vs-heapsort)
- [Importance of Stability in Sorting](https://stackoverflow.com/questions/1517793/what-is-stability-in-sorting-algorithms-and-why-is-it-important)
### Most Common Sorts
- [Merge Sort | Brilliant.org](https://brilliant.org/wiki/merge/)
- [Quicksort | Brilliant.org](https://brilliant.org/wiki/quick-sort/)
- [Heap Sort | Brilliant.org](https://brilliant.org/wiki/heap-sort/)
- [Radix Sort | Brilliant.org](https://brilliant.org/wiki/radix-sort/ "Non-Comparison Sort")
- [Radix Sort Visualization](https://www.cs.usfca.edu/~galles/visualization/RadixSort.html)
- [Counting Sort | Brilliant.org](https://brilliant.org/wiki/counting-sort/ "Non-Comparison Sort")
- [Counting Sort Visualization](https://www.cs.usfca.edu/~galles/visualization/CountingSort.html)
================================================
FILE: Algorithms/Recursion/Basics.ts
================================================
function inception(repeat: number): string {
// 1. Base Case(s)
if (repeat === 0) return 'Done!\n'; // Base Case(s) must be written first in method
// 2?. Input Validation
if (repeat < 1) return 'Too small!\n'; // Input validation should occur after base case(s)
console.log('Counter:', repeat);
// 3. Recursive Call
return inception(repeat-1); // The recursive call should return itself so the calculated value can bubble up
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
console.log(inception(5));
console.log(inception(1));
console.log(inception(-1));
// RUN: deno run Algorithms/Recursion/Basics.ts
}
// --------------------------- Terminal Output: ---------------------------
// Counter: 5
// Counter: 4
// Counter: 3
// Counter: 2
// Counter: 1
// Done!
//
// Counter: 1
// Done!
//
// Too small!
================================================
FILE: Algorithms/Recursion/Factorial.ts
================================================
function calcFactorialRecursive(input: number): number {
if (input <= 1) return 1;
return input * calcFactorialRecursive(input-1);
}
function calcFactorialIterative(input: number): number | undefined {
if (input < 0) return undefined;
let factorial = 1;
for (let i=2; i <= input; ++i) {
factorial *= i;
}
return factorial;
}
function validateFactorialInput(input: number): boolean {
return input>=0;
}
function printIterativeFactorial(input: number) {
if (!validateFactorialInput(input)) {
console.log("Input", input, "is invalid -_-'");
return;
}
console.log('Iterative Factorial', input+':', calcFactorialIterative(input));
}
function printRecursiveFactorial(input: number) {
if (!validateFactorialInput(input)) {
console.log("Input", input, "is invalid -_-'");
return;
}
console.log('Recursive Factorial', input+':', calcFactorialRecursive(input));
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
printIterativeFactorial(0);
printIterativeFactorial(1);
printIterativeFactorial(2);
printIterativeFactorial(3);
printIterativeFactorial(5);
printRecursiveFactorial(4);
printRecursiveFactorial(0);
printRecursiveFactorial(-1);
printRecursiveFactorial(170);
printIterativeFactorial(171);
// RUN: deno run Algorithms/Recursion/Factorial.ts
}
// --------------------------- Terminal Output: ---------------------------
// Iterative Factorial 0: 1
// Iterative Factorial 1: 1
// Iterative Factorial 2: 2
// Iterative Factorial 3: 6
// Iterative Factorial 5: 120
// Recursive Factorial 4: 24
// Recursive Factorial 0: 1
// Input -1 is invalid -_-'
// Recursive Factorial 170: 7.257415615307994e+306
// Iterative Factorial 171: Infinity
================================================
FILE: Algorithms/Recursion/Fibonacci.ts
================================================
// ---------------- Fibonacci Sequence ----------------
// 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144...
// Time Complexity: O(2^n) Space Complexity: O(2^n)
function fibonacciRecursive(nthElement: number): number | any {
// Base Cases
if (nthElement === 1) return 0;
if (nthElement === 2) return 1;
//Input Validation
if (nthElement < 1) return undefined;
// Recursive Call: The nth element equals the sum of the previous 2 elements.
return fibonacciRecursive(nthElement-2) + fibonacciRecursive(nthElement-1);
}
// Time Complexity: O(n) Space Complexity: O(1)
function fibonacciIterative(nthElement: number): number | undefined {
if (nthElement < 1) return undefined;
else nthElement = Math.floor(nthElement);
let previous = 0;
let current = 1;
if (nthElement === 1) return previous;
if (nthElement === 2) return current;
let fibonacci: number = 0;
for (let i = 3; i <= nthElement; ++i) {
fibonacci = previous + current;
previous = current;
current = fibonacci;
}
return fibonacci;
}
function validateFibonacciInput(nthElement: number) {
return nthElement>0;
}
function printFibonacciIterative(nthElement: number) {
console.log("Fibonacci Iterative", nthElement+':', fibonacciIterative(nthElement));
}
function printFibonacciRecursive(nthElement: number) {
if(!validateFibonacciInput(nthElement)) {
console.log("Input", nthElement, "is invalid -_-'");
return;
}
console.log("Fibonacci Recursive", nthElement+':', fibonacciRecursive(nthElement));
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
console.log('------------ Iterative ------------');
printFibonacciIterative(0);
printFibonacciIterative(1);
printFibonacciIterative(2);
printFibonacciIterative(3);
printFibonacciIterative(4);
printFibonacciIterative(5);
printFibonacciIterative(6);
printFibonacciIterative(9);
printFibonacciIterative(42);
printFibonacciIterative(50);
printFibonacciIterative(100);
console.log('\n------------ Recursive ------------');
printFibonacciRecursive(-1);
printFibonacciRecursive(0);
printFibonacciRecursive(1);
printFibonacciRecursive(2);
printFibonacciRecursive(3);
printFibonacciRecursive(4);
printFibonacciRecursive(5);
printFibonacciRecursive(7);
printFibonacciRecursive(8);
printFibonacciRecursive(42); // Notice how much longer this takes than the iterative version
// RUN: deno run Algorithms/Recursion/Fibonacci.ts
}
// --------------------------- Terminal Output: ---------------------------
// ------------ Iterative ------------
// Fibonacci Iterative 0: undefined
// Fibonacci Iterative 1: 0
// Fibonacci Iterative 2: 1
// Fibonacci Iterative 3: 1
// Fibonacci Iterative 4: 2
// Fibonacci Iterative 5: 3
// Fibonacci Iterative 6: 5
// Fibonacci Iterative 9: 21
// Fibonacci Iterative 42: 165580141
// Fibonacci Iterative 50: 7778742049
// Fibonacci Iterative 100: 218922995834555200000
// ------------ Recursive ------------
// Input -1 is invalid -_-'
// Input 0 is invalid -_-'
// Fibonacci Recursive 1: 0
// Fibonacci Recursive 2: 1
// Fibonacci Recursive 3: 1
// Fibonacci Recursive 4: 2
// Fibonacci Recursive 5: 3
// Fibonacci Recursive 7: 8
// Fibonacci Recursive 8: 13
// Fibonacci Recursive 42: 165580141
================================================
FILE: Algorithms/Searching/Basics.ts
================================================
var beasts = ['Centaur', 'Godzilla', 'Mosura', 'Minotaur', 'Hydra', 'Nessie'];
beasts.indexOf('Godzilla'); // Index: 1
beasts.findIndex(function(item){ // Index: 1
return item === 'Godzilla';
});
beasts.find(function(item){ // 'Godzilla'
return item === 'Godzilla';
});
beasts.includes('Godzilla'); // true
================================================
FILE: Algorithms/Searching/BreadthFirstTraversal.ts
================================================
import BST from '../../Data-Structures/Trees/BinarySearchTree.ts';
import Node from '../../Data-Structures/Trees/BinaryTreeNode.ts';
import Queue from '../../Data-Structures/Sequential/Queue.ts';
function recursiveBFT(nodeQueue: Queue<Node>, nodesTraversed: Array<number>): Array<number> {
if (nodeQueue.getLength() === 0) return nodesTraversed;
let currentNode: Node = nodeQueue.dequeue();
nodesTraversed.push(currentNode.getValue());
if (currentNode.hasLeft()) nodeQueue.enqueue(currentNode.getLeft());
if (currentNode.hasRight()) nodeQueue.enqueue(currentNode.getRight());
return recursiveBFT(nodeQueue, nodesTraversed);
}
function breadthFirstTraversal(tree: BST) {
const root = tree.getRoot();
if (!root) return false;
const nodesTraversed: number[] = [];
const nodeQueue = new Queue<Node>();
nodeQueue.enqueue(root);
return recursiveBFT(nodeQueue, nodesTraversed);
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
const tree = new BST();
// 9
// 4 20
// 1 6 15 170
tree.insert(9);
tree.insert(4);
tree.insert(6);
tree.insert(20);
tree.insert(170);
tree.insert(15);
tree.insert(1);
console.log(breadthFirstTraversal(tree));
// RUN: deno run Algorithms/Searching/BreadthFirstTraversal.ts
}
// --------------------------- Terminal Output: ---------------------------
// [
// 9, 4, 20, 1,
// 6, 15, 170
// ]
================================================
FILE: Algorithms/Searching/DepthFirstTraversals.ts
================================================
import BST from '../../Data-Structures/Trees/BinarySearchTree.ts';
import Node from '../../Data-Structures/Trees/BinaryTreeNode.ts';
export function inorderDFT(tree: BST) {
const root = tree.getRoot();
if (!root) return false;
const nodesTraversed: number[] = [];
return traverseInOrder(root, nodesTraversed);
/**
* Recursive DFS on Binary Search Tree via inorder traversal
* @param node Binary node to traverse
* @param nodesTraversed Array of all nodes reached inorder
*/
function traverseInOrder(node: Node, nodesTraversed: Array<number>) {
if (node.hasLeft()) traverseInOrder(node.getLeft(), nodesTraversed);
nodesTraversed.push(node.getValue());
if (node.hasRight()) traverseInOrder(node.getRight(), nodesTraversed);
return nodesTraversed;
}
}
export function preorderDFT(tree: BST) {
const root = tree.getRoot();
if (!root) return false;
const nodesTraversed: number[] = [];
return traversePreOrder(root, nodesTraversed);
/**
* Recursive DFS on Binary Search Tree via preorder traversal
* @param node Binary node to traverse
* @param nodesTraversed Array of all nodes reached preorder
*/
function traversePreOrder(node: Node, nodesTraversed: Array<number>) {
nodesTraversed.push(node.getValue());
if (node.hasLeft()) traversePreOrder(node.getLeft(), nodesTraversed);
if (node.hasRight()) traversePreOrder(node.getRight(), nodesTraversed);
return nodesTraversed;
}
}
export function postorderDFT(tree: BST) {
const root = tree.getRoot();
if (!root) return false;
const nodesTraversed: number[] = [];
return traversePostOrder(root, nodesTraversed);
/**
* Recursive DFS on Binary Search Tree via postorder traversal
* @param node Binary node to traverse
* @param nodesTraversed Array of all nodes reached postorder
*/
function traversePostOrder(node: Node, nodesTraversed: Array<number>) {
if (node.hasLeft()) traversePostOrder(node.getLeft(), nodesTraversed);
if (node.hasRight()) traversePostOrder(node.getRight(), nodesTraversed);
nodesTraversed.push(node.getValue());
return nodesTraversed;
}
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
const tree = new BST();
// 9
// 4 20
// 1 6 15 170
tree.insert(9);
tree.insert(4);
tree.insert(6);
tree.insert(20);
tree.insert(170);
tree.insert(15);
tree.insert(1);
console.log('Inorder:', inorderDFT(tree));
console.log('Preorder:', preorderDFT(tree));
console.log('Postorder:', postorderDFT(tree));
// RUN: deno run Algorithms/Searching/DepthFirstTraversals.ts
}
// --------------------------- Terminal Output: ---------------------------
// Inorder: [
// 1, 4, 6, 9,
// 15, 20, 170
// ]
// Preorder: [
// 9, 4, 1, 6,
// 20, 15, 170
// ]
// Postorder: [
// 1, 6, 4, 15,
// 170, 20, 9
// ]
================================================
FILE: Algorithms/Searching/Exercise_BFSDFSUseCases.md
================================================
# Graph Traversal Use Cases
## Which traversal algorithm would be best for each situation? (BFS or DFS)
1) If you know a solution is not far from the root of the tree:
2) If the tree is very deep and solutions are rare,
3) If the tree is very wide:
4) If solutions are frequent but located deep in the tree
5) determining whether a path exists between two nodes
6) Finding the shortest path
## Answers
1) BFS
2) BFS (DFS will take longer)
3) DFS (BFS is too memory intensive for wide trees)
4) DFS
5) DFS
6) BFS
================================================
FILE: Algorithms/Sorting/Basics.ts
================================================
const spanish = ['único', 'árbol', 'cosas', 'fútbol'];
spanish.sort(function(a,b) {
return a.localeCompare(b, 'es');
});
console.log(spanish);
// OUTPUT: [ "cosas", "fútbol", "árbol", "único" ]
// RUN: deno run Algorithms/Sorting/Basics.ts
================================================
FILE: Algorithms/Sorting/BubbleSort.ts
================================================
function bubbleSort(numbersArr: Array<number>) {
for (let i=0; i < numbersArr.length-1; ++i) {
for (let j=0; j < numbersArr.length-1-i; ++j) {
if (numbersArr[j] > numbersArr[j+1]) {
numbersArr[j+1] = numbersArr[j] + numbersArr[j+1];
numbersArr[j] = numbersArr[j+1] - numbersArr[j];
numbersArr[j+1] = numbersArr[j+1] - numbersArr[j];
}
}
}
return numbersArr;
}
function bubbleSortStrings(stringArr: Array<string>) {
let placeholder: string;
for (let i=0; i < stringArr.length-1; ++i) {
for (let j=0; j < stringArr.length-1-i; ++j) {
if (stringArr[j] > stringArr[j+1]) {
placeholder = stringArr[j];
stringArr[j] = stringArr[j+1];
stringArr[j+1] = placeholder;
}
}
}
return stringArr;
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
const numbers1 = [9,6,5,3,1,8,7,2,4];
const numbers2 = [99, 44, 6, 2, 1, 5, 63, 87, 283, 4, 0];
const colors = ["white", "black", "green", "blue", "orange"];
console.log(bubbleSort(numbers1));
console.log(bubbleSort(numbers2));
console.log(bubbleSortStrings(colors));
// RUN: deno run Algorithms/Sorting/BubbleSort.ts
}
// --------------------------- Terminal Output: ---------------------------
// [
// 1, 2, 3, 4, 5,
// 6, 7, 8, 9
// ]
// [
// 0, 1, 2, 4, 5,
// 6, 44, 63, 87, 99,
// 283
// ]
// [ "black", "blue", "green", "orange", "white" ]
================================================
FILE: Algorithms/Sorting/Data/PlantFamilies.ts
================================================
export const plant_families = {
short_list: [
"Loranthaceae",
"Clusiaceae",
"Aristolochiaceae",
"Myrtaceae",
"Araliaceae",
"Ericaceae",
"Dryopteridaceae",
"Boraginaceae",
"Juncaceae",
"Pottiaceae",
"Amaranthaceae",
"Polemoniaceae",
"Pteridaceae",
"Arthopyreniaceae",
"Campanulaceae",
"Brachytheciaceae",
"Caryophyllaceae",
"Acanthaceae",
"Sematophyllaceae",
"Lamiaceae",
"Lecanoraceae",
"Brassicaceae",
"Rosaceae",
"Orchidaceae",
"Sapotaceae",
"Oleaceae",
"Sapindaceae",
"Amblystegiaceae",
"Droseraceae",
"Lecideaceae",
"Gentianaceae",
"Fabaceae",
"Combretaceae",
"Aspleniaceae",
"Cyperaceae",
"Arthoniaceae",
"Chenopodiaceae",
"Saxifragaceae",
"Euphorbiaceae",
"Passifloraceae",
"Parmeliaceae",
"Celastraceae",
"Myristicaceae",
"Andreaeaceae",
"Poaceae",
"Crassulaceae",
"Asteraceae",
"Stereocaulaceae",
"Onagraceae",
"Verrucariaceae",
"Apiaceae",
"Liliaceae",
"Polygonaceae",
"Convolvulaceae",
"Scrophulariaceae",
"Malvaceae",
],
medium_list: [
"Burseraceae",
"Buxbaumiaceae",
"Encalyptaceae",
"Hymeneliaceae",
"Roccellaceae",
"Peltigeraceae",
"Ephedraceae",
"Grammitidaceae",
"Santalaceae",
"Pyrolaceae",
"Aristolochiaceae",
"Placynthiaceae",
"Marantaceae",
"Ochnaceae",
"Thelotremataceae",
"Staphyleaceae",
"Calycanthaceae",
"Pleuroziopsidaceae",
"Zingiberaceae",
"Disceliaceae",
"Proteaceae",
"Selaginellaceae",
"Sphagnaceae",
"Theophrastaceae",
"Malpighiaceae",
"Limnanthaceae",
"Viscaceae",
"Gyalectaceae",
"Cladoniaceae",
"Graphidaceae",
"Pyrenulaceae",
"Geraniaceae",
"Micareaceae",
"Hippuridaceae",
"Dryopteridaceae",
"Dicranaceae",
"Commelinaceae",
"Krameriaceae",
"Ruppiaceae",
"Fumariaceae",
"Thelenellaceae",
"Splachnaceae",
"Thymelaeaceae",
"Najadaceae",
"Simaroubaceae",
"Araliaceae",
"Vitaceae",
"Corticiaceae",
"Sarraceniaceae",
"Zamiaceae",
"Fontinalaceae",
"Trypetheliaceae",
"Lobariaceae",
"Polytrichaceae",
"Gentianaceae",
"Acarosporaceae",
"Equisetaceae",
"Mniaceae",
"Sapindaceae",
"Cornaceae",
"Ditrichaceae",
"Catillariaceae",
"Portulacaceae",
"Cabombaceae",
"Bryaceae",
"Loasaceae",
"Cistaceae",
"Hypnaceae",
"Dipsacaceae",
"Crassulaceae",
"Arecaceae",
"Lecideaceae",
"Pinaceae",
"Plantaginaceae",
"Juglandaceae",
"Flacourtiaceae",
"Combretaceae",
"Melastomataceae",
"Uncertain",
"Ascomycota",
"Family",
"Monoblastiaceae",
"Capparaceae",
"Peltulaceae",
"Pontederiaceae",
"Araceae",
"Rhamnaceae",
"Amblystegiaceae",
"Celastraceae",
"Anacardiaceae",
"Sapotaceae",
"Piperaceae",
"Hydrocharitaceae",
"Sematophyllaceae",
"Loranthaceae",
"Primulaceae",
"Potamogetonaceae",
"Teloschistaceae",
"Cuscutaceae",
"Brachytheciaceae",
"Opegraphaceae",
"Bignoniaceae",
"Melaspileaceae",
"Dennstaedtiaceae",
"Verrucariaceae",
"Papaveraceae",
"Isoetaceae",
"Saururaceae",
"Onagraceae",
"Polygalaceae",
"Pteridaceae",
"Leskeaceae",
"Pertusariaceae",
"Nymphaeaceae",
"Apocynaceae",
"Nyctaginaceae",
"Valerianaceae",
"Rutaceae",
"Rubiaceae",
"Alectoriaceae",
"Juncaceae",
"Moraceae",
"Orchidaceae",
"Acanthaceae",
"Solanaceae",
"Urticaceae",
"Myrtaceae",
"Pottiaceae",
"Parmeliaceae",
"Aspleniaceae",
"Cucurbitaceae",
"Thelypteridaceae",
"Linaceae",
"Lecanoraceae",
"Smilacaceae",
"Stereocaulaceae",
"Chrysobalanaceae",
"Amaranthaceae",
"Violaceae",
"Styracaceae",
"Cupressaceae",
"Hydrangeaceae",
"Hippocastanaceae",
"Lauraceae",
"Asclepiadaceae",
"Tamaricaceae",
"Aizoaceae",
"Calymperaceae",
"Porpidiaceae",
"Andreaeaceae",
"Cactaceae",
"Bromeliaceae",
"Mycoblastaceae",
"Crossosomataceae",
"Rhytidiaceae",
"Orthotrichaceae",
"Ericaceae",
"Convolvulaceae",
"Campanulaceae",
"Magnoliaceae",
"Euphorbiaceae",
"Polemoniaceae",
"Iridaceae",
"Zygophyllaceae",
"Orobanchaceae",
"Saxifragaceae",
"Caryophyllaceae",
"Fagaceae",
"Meteoriaceae",
"Lamiaceae",
"Neckeraceae",
"Caprifoliaceae",
"Malvaceae",
"Lythraceae",
"Aquifoliaceae",
"Ranunculaceae",
"Alismataceae",
"Chenopodiaceae",
"Physciaceae",
"Hymenophyllaceae",
"Theaceae",
"Liliaceae",
"Salicaceae",
"Fabaceae",
"Apiaceae",
"Gesneriaceae",
"Hydrophyllaceae",
"Fissidentaceae",
"Rosaceae",
"Brassicaceae",
"Verbenaceae",
"Marcgraviaceae",
"Boraginaceae",
"Cyperaceae",
"Agavaceae",
"Lycopodiaceae",
"Myrsinaceae",
"Loganiaceae",
"Scrophulariaceae",
"Asteraceae",
"Sterculiaceae",
"Poaceae",
"Polygonaceae",
"Aceraceae",
],
};
================================================
FILE: Algorithms/Sorting/Exercise_SortingUseCases.md
================================================
# Sorting Use Cases
## Which sorting algorithm would be a good candidate for each situation?
1) Sort 10 schools around your house by distance.
2) eBay sorts listings by the current Bid amount.
3) Sport scores on ESPN.
4) Massive database (can't fit all into memory) needs to sort through past year's user data.
5) Almost sorted Udemy review data needs to update and add 2 new reviews.
6) Temperature Records for the past 50 years in Canada.
7) Large user name database needs to be sorted. Data is very random.
8) You want to teach sorting for the first time.
## Potential Candidates
1) Insertion Sort
2) Radix/Counting Sort
3) Quicksort
4) Merge Sort
5) Insertion Sort
6) Radix/Counting Sort or Quicksort
7) Mergesort/Quicksort
8) Bubble Sort, Selection Sort
================================================
FILE: Algorithms/Sorting/InsertionSort.ts
================================================
import { plant_families } from './Data/PlantFamilies.ts';
function insertionSort(inputArr: number[] | string[]) {
if (typeof inputArr[0] === 'number') {
for (let i=0; i < inputArr.length; ++i) {
if (inputArr[i] < inputArr[0]) {
const element = inputArr.splice(i,1) as number[];
// Move element to the first position
(inputArr as number[]).unshift(element[0]);
}
else {
// Only sort number smaller than preceding number
if (inputArr[i] < inputArr[i-1]) {
// Find where element's sorted position
for (var j = 1; j < i; j++) {
if (inputArr[i] >= inputArr[j-1] && inputArr[i] < inputArr[j]) {
// Move element to the sorted spot
inputArr.splice(j,0,inputArr.splice(i,1)[0] as number);
}
}
}
}
}
}
else if (typeof inputArr[0] === 'string') {
for (let i=0; i < inputArr.length; ++i) {
if (inputArr[i] < inputArr[0]) {
const element = inputArr.splice(i,1) as string[];
// Move element to the first position
(inputArr as string[]).unshift(element[0]);
}
else {
// Only sort number smaller than preceding number
if (inputArr[i] < inputArr[i-1]) {
// Find where element's sorted position
for (var j = 1; j < i; j++) {
if (inputArr[i] >= inputArr[j-1] && inputArr[i] < inputArr[j]) {
// Move element to the sorted spot
inputArr.splice(j,0,inputArr.splice(i,1)[0] as string);
}
}
}
}
}
}
return inputArr;
}
function executionTime(method: any): string {
const t0 = performance.now();
method(plant_families.medium_list);
const t1 = performance.now();
return (t1-t0) + 'ms';
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
const numbers1 = [9,6,5,3,1,8,7,2,4];
const numbers2 = [99, 44, 6, 2, 1, 5, 63, 87, 283, 4, 0];
const colors = ["white", "black", "green", "blue", "orange"];
console.log('\n------------------ Insertion Sort ------------------');
console.log(insertionSort(numbers1));
console.log(insertionSort(numbers2));
console.log(insertionSort(colors));
console.log('\n---------------- Algorithm Benchmarks ----------------');
const a1 = Object.create({});
a1.run_1 = executionTime(insertionSort);
a1.run_2 = executionTime(insertionSort);
a1.run_3 = executionTime(insertionSort);
// const a2 = Object.create({});
// a2.run_1 = executionTime(insertionSortModified);
// a2.run_2 = executionTime(insertionSortModified);
// a2.run_3 = executionTime(insertionSortModified);
console.table([a1]);
// RUN: deno run Algorithms/Sorting/InsertionSort.ts
}
// --------------------------- Terminal Output: ---------------------------
//
// ------------------ Insertion Sort ------------------
// [
// 1, 2, 3, 4, 5,
// 6, 7, 8, 9
// ]
// [
// 0, 1, 2, 4, 5,
// 6, 44, 63, 87, 99,
// 283
// ]
// [ "black", "blue", "green", "orange", "white" ]
//
// ------------- Modified Insertion Sort --------------
// [
// 1, 2, 3, 4, 5,
// 6, 7, 8, 9
// ]
// [
// 0, 1, 2, 4, 5,
// 6, 44, 63, 87, 99,
// 283
// ]
// [ "black", "blue", "green", "orange", "white" ]
//
// ---------------- Algorithm Benchmarks ----------------
// ┌───────┬────────┬────────┬───────┐
// │ (idx) │ run_1 │ run_2 │ run_3 │
// ├───────┼────────┼────────┼───────┤
// │ 0 │ "32ms" │ "34ms" │ "2ms" │
// │ 1 │ "10ms" │ "12ms" │ "4ms" │
// └───────┴────────┴────────┴───────┘
================================================
FILE: Algorithms/Sorting/MergeSort.ts
================================================
function merge(left: any[], right: any[]): Array<any> {
const result = [];
let leftIndex = 0;
let rightIndex = 0;
while (
leftIndex < left.length &&
rightIndex < right.length
) {
if (left[leftIndex] <= right[rightIndex]) {
result.push(left[leftIndex]);
++leftIndex;
} else {
result.push(right[rightIndex]);
++rightIndex;
}
}
// console.log('Result:', result);
// console.log('\tLeft:', left.slice(leftIndex));
// console.log('\tRight:', right.slice(rightIndex));
return result.concat(left.slice(leftIndex)).concat(right.slice(rightIndex)); // Add remaining elements on either side
}
function mergeSort(inputArr: string[] | number[]): Array<any> {
if (inputArr.length === 1) return inputArr; // Base Case
// Split Array in into right and left
const middleIndex = Math.floor(inputArr.length / 2);
const left = inputArr.slice(0, middleIndex);
const right = inputArr.slice(middleIndex);
// console.log('left:', left);
// console.log('right:', right);
return merge(
mergeSort(left),
mergeSort(right),
);
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
const numbers1 = [9, 6, 5, 3, 1, 8, 7, 2, 4];
const numbers2 = [99, 44, 6, 2, 1, 5, 63, 87, 283, 4, 0];
const colors = ["white", "black", "green", "blue", "orange"];
console.log(mergeSort(numbers1));
console.log(mergeSort(numbers2));
console.log(mergeSort(colors));
// RUN: deno run Algorithms/Sorting/MergeSort.ts
}
// --------------------------- Terminal Output: ---------------------------
// [
// 1, 2, 3, 4, 5,
// 6, 7, 8, 9
// ]
// [
// 0, 1, 2, 4, 5,
// 6, 44, 63, 87, 99,
// 283
// ]
// [ "black", "blue", "green", "orange", "white" ]
================================================
FILE: Algorithms/Sorting/QuickSort.ts
================================================
/**
* Given an array, swaps two elements at the specified positions (indices).
* @param array Array in which to swap elements between two positions
* @param pos1 Index of first element's position
* @param pos2 Index of second element's position
*/
function swap(array: Array<any>, pos1: number, pos2: number) {
let temp = array[pos1];
array[pos1] = array[pos2];
array[pos2] = temp;
}
function partition(array: Array<any>, pivotIndex: number, leftBound: number, rightBound: number){
let pivot = array[pivotIndex];
let partitionIndex = leftBound;
for (let i = leftBound; i < rightBound; ++i) {
if (array[i] < pivot) {
swap(array, i, partitionIndex);
++partitionIndex;
}
}
swap(array, rightBound, partitionIndex);
return partitionIndex;
}
/**
* Sort an array of numbers or strings using Quick Sort
* @param array Complete array to be sorted
* @param leftBound Index of left-most element for section to be sorted
* @param rightBound Index of right-most element for section to be sorted
* @returns Returns sorted array
*/
function quickSort(array: number[] | string[], leftBound: number, rightBound: number): Array<any> {
let pivotIndex: number;
let partitionIndex: number;
if (leftBound < rightBound) {
pivotIndex = rightBound;
partitionIndex = partition(array, pivotIndex, leftBound, rightBound);
// Sort left & right sub-sections
quickSort(array, leftBound, partitionIndex-1);
quickSort(array, partitionIndex+1, rightBound);
}
return array;
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
const numbers1 = [9, 6, 5, 3, 1, 8, 7, 2, 4];
const numbers2 = [99, 44, 6, 2, 1, 5, 63, 87, 283, 4, 0];
const colors = ["white", "black", "green", "blue", "orange"];
console.log(quickSort(numbers1, 0, numbers1.length-1));
console.log(quickSort(numbers2, 0, numbers2.length-1));
console.log(quickSort(colors, 0, colors.length-1));
// RUN: deno run Algorithms/Sorting/QuickSort.ts
}
// --------------------------- Terminal Output: ---------------------------
// [
// 1, 2, 3, 4, 5,
// 6, 7, 8, 9
// ]
// [
// 0, 1, 2, 4, 5,
// 6, 44, 63, 87, 99,
// 283
// ]
// [ "black", "blue", "green", "orange", "white" ]
================================================
FILE: Algorithms/Sorting/SelectionSort.ts
================================================
function swap(pos1: number, pos2: number, inputArr: Array<any>): void {
const placeholder = inputArr[pos1];
inputArr[pos1] = inputArr[pos2];
inputArr[pos2] = placeholder;
}
function selectionSort(inputArr: Array<number> | Array<string>): Array<any> {
let minValue: number | string;
let minIndex: number;
for (let i=0; i < inputArr.length-1; ++i) {
minValue = inputArr[i];
minIndex = i;
for (let j=i+1; j <= inputArr.length-1; ++j) {
if (inputArr[j] < minValue) {
minValue = inputArr[j];
minIndex = j;
}
}
swap(i, minIndex, inputArr);
}
return inputArr;
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
const numbers1 = [9,6,5,3,1,8,7,2,4];
const numbers2 = [99, 44, 6, 2, 1, 5, 63, 87, 283, 4, 0];
const colors = ["white", "black", "green", "blue", "orange"];
console.log(selectionSort(numbers1));
console.log(selectionSort(numbers2));
console.log(selectionSort(colors));
// RUN: deno run Algorithms/Sorting/SelectionSort.ts
}
// --------------------------- Terminal Output: ---------------------------
// [
// 1, 2, 3, 4, 5,
// 6, 7, 8, 9
// ]
// [
// 0, 1, 2, 4, 5,
// 6, 44, 63, 87, 99,
// 283
// ]
// [ "black", "blue", "green", "orange", "white" ]
================================================
FILE: Big-O/Ex1.ts
================================================
// Exercise 1 -----------------------------------------
function anotherFunction() {
// unknown runtime
}
function funChallenge(input: Array<any>): number {
let a = 10; // O(1)
a = 50 + 3; // O(1)
for (let i = 0; i < input.length; i++) { // O(n)
anotherFunction(); // O(n)
let stranger = true; // O(n)
a++; // O(n)
}
return a; // O(1)
}
const numbersArr = [1,2,3,4,5];
funChallenge(numbersArr); // Time Complexity: O(3 + 4n) ~ O(n)
================================================
FILE: Big-O/Ex2.ts
================================================
// Exercise 2 -----------------------------------------
function anotherFunChallenge(input: number): void {
let a = 5; // O(1)
let b = 10; // O(1)
let c = 50; // O(1)
for (let i = 0; i < input; i++) { // O(n)
let x = i + 1; // O(n)
let y = i + 2; // O(n)
let z = i + 3; // O(n)
}
for (let j = 0; j < input; j++) { // O(n)
let p = j * 2; // O(n)
let q = j * 2; // O(n)
}
let whoAmI = "I don't know"; // O(1)
}
anotherFunChallenge(7); // Time Complexity: O(4 + 7n) ~ O(n)
================================================
FILE: Big-O/Hello_Big_O.ts
================================================
const nemo = ['nemo'];
const fishColony = ['dory', 'bruce', 'marlin', 'nemo', 'gill', 'bloat', 'nigel', 'squirt', 'darla', 'hank'];
const largeArr = new Array(10_000_000).fill('squish');
function findNemo(fishes: Array<string>): string {
let t0 = performance.now(); // O(1)
let isNemoFound = false; // O(1)
for (let i = 0; i < fishes.length; i++) { // O(n)
if (fishes[i] === 'nemo') { // O(n)
isNemoFound = true; // O(n)
break; // O(1)
}
}
let t1 = performance.now(); // O(1)
console.log("Call to find Nemo took " + (t1 - t0) + "ms."); // O(1)
return isNemoFound ? "Found NEMO!" : "Where did Nemo go?!"; // O(1)
}
function getFirstFish(fishes: Array<string>) {
return fishes[0].charAt(0).toUpperCase() + fishes[0].substring(1).toLowerCase(); // O(1)
}
console.log(findNemo(fishColony)); // Time Complexity: O(n)
console.log(findNemo(largeArr)); // Time Complexity: O(n)
console.log(getFirstFish(fishColony), "just keeps swimming!"); // Time Complexity: O(1)
================================================
FILE: Big-O/README.md
================================================
# Algorithm Time-Complexity Analysis
**Goal:** Understand how the runtime of an algorithm is affected by an increasing number of elements.
## 5 Rules
1. Analyze the worst case performance of the algorithm, i.e. Big O
2. Add steps in order (+); multiply nested steps (*)
3. Different inputs should have different variables, e.g. O(a+b)
4. Remove constants
5. Drop non-dominants
## 3 Types
### 1. Big O – Worst Case
#### Ideal
O(1) – Constant
O(log n) – Logarithmic
O(n) – Linear
#### Acceptable
O(n * log n) – Log Linear
#### Avoid
O(n^2) – Quadratic
O(2^n) – Exponential
O(n!) – Factorial
### 2. Big Θ – Average/Tight Case
### 3. Big Ω – Best Case
## Resources
- [Big-O Algorithm Complexity Cheat Sheet (Know Thy Complexities!) @ericdrowell](https://www.bigocheatsheet.com/ "Big O Cheat Sheet")
- [Practical Java Examples of the Big O Notation](https://www.baeldung.com/java-algorithm-complexity "Big O Examples")
================================================
FILE: Big-O/Rule3.ts
================================================
// Rule 3: Different inputs should have different variables.--------------------
function compressBoxes(fullBoxes: Array<string>, emptyBoxes: Array<string>) {
fullBoxes.forEach((box) => { // O(a)
console.log(box);
});
emptyBoxes.forEach((box) => { // O(b)
console.log(box);
});
}
// Time Complexity: O(a+b)
================================================
FILE: Big-O/n_squared.ts
================================================
// Examples of Quadratic Big O Runtime — O(n^2) ------------------
const boxes = ["a", "b", "c", "d", "e"];
function logAllPairs(array: Array<any>): void {
for (let i = 0; i < array.length; i++) { // O(n)
for (let j = 0; j < array.length; j++) { // O(n)
console.log(array[i], array[j]); // O(n)
}
}
}
function printNumbersThenPairSums(numbers: Array<number>): void {
console.log("these are the numbers:");
numbers.forEach(function (number) { // O(n)
console.log(number);
});
console.log("and these are their sums:");
numbers.forEach(function (firstNumber) { // O(n)
numbers.forEach(function (secondNumber) { // O(n)
console.log(firstNumber + secondNumber); // O(n)
});
});
}
logAllPairs(boxes); // O(n * 2n) ~ O(n^2)
printNumbersThenPairSums([1, 2, 3, 4, 5]); // O(n + n*2n) ~ O(n^2)
================================================
FILE: Data-Structures/Arrays/Basics.ts
================================================
// RUN: deno run Data-Structures/Arrays/Basics.ts
const teamAvatar = ['Aang','Appa','Momo','Katara','Sokka'];
// Push adds an element to the end of the array
teamAvatar.push('Yue'); // O(1)
// Pop removes and returns the last element
console.log(teamAvatar.pop(), 'turned into the moon!!!'); // O(1)
console.log(teamAvatar.pop(), "is in disbelief..."); // O(1)
console.log(teamAvatar);
console.log('Team Avatar is', teamAvatar.push('Sokka'), 'strong.');
// Unshift adds the specified elements to the beginning of the array
teamAvatar.unshift('Toph'); // O(n)
console.log('Toph joins the team!');
// Splice(i, n) removes n elements starting from index i
teamAvatar.splice(2, 1); // O(n)
console.log('Appa was captured?!?!', teamAvatar);
// Splice(i, 0, [elements]) inserts [elements] at index i
teamAvatar.splice(2, 0, 'Appa'); // O(n)
console.log('Zuko saved Appa!!!', teamAvatar);
================================================
FILE: Data-Structures/Arrays/MyArray.ts
================================================
type NumIndexedObject = { [index: number]: any };
export default class MyArray<T> {
public length: number;
private data: NumIndexedObject;
constructor() {
this.length = 0;
this.data = Object.create({});
}
/**
* Get element at given index.
* @param index Index of value to return
* @returns Value, or null if non-existant
*/
public get(index: number): T | null {
if(index > 0 && index < this.length) {
return this.data[index];
}
return null;
}
/**
* Add element to end of array,i.e. at index Array.length.
* @param item Value/object to push
* @returns Length of array after push
*/
public push(item: T): number {
this.data[this.length] = item; // Add item to end of array
++this.length; // Add 1 to array length
return this.length;
}
/**
* Remove the last element of array.
* @returns Value/object at last index, or null if empty array
*/
public pop(): T | null {
if(this.length > 0) {
const lastItem = this.data[this.length-1]; // Retrieve last item
delete this.data[this.length-1]; // Delete last item
--this.length; // Decrement array length by 1
return lastItem;
}
return null;
}
/**
* Delete item at given index.
* @param index Numerical position to delete
* @returns Value/object at index, or null if empty array
*/
public deleteIndex(index: number): T | null {
if(index >= 0 && index < this.length) {
const requestedItem = this.data[index];
this._shiftItemsLeftAfterIndex(index);
return requestedItem;
}
return null;
}
/**
* Insert a given value (item) at specified index
* @param index Numerical position to insert at
* @param item Value/object to insert
* @returns Length of array after insertion, or null if failed insertion
*/
public insertItemAtIndex(index: number, item: T): number | null {
if(index >= 0 && index < this.length) {
this._shiftItemsRightAtIndex(index);
this.data[index] = item;
return this.length;
}
return null;
}
private _shiftItemsLeftAfterIndex(index: number): void {
for (let i=index; i < this.length-1; ++i) {
this.data[i] = this.data[i+1];
}
--this.length;
delete this.data[this.length];
}
private _shiftItemsRightAtIndex(index: number): void {
++this.length;
for (let i=this.length-1; i > index; --i) {
this.data[i] = this.data[i-1];
}
delete this.data[index];
}
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
let helloArray = new MyArray<string>();
helloArray.push('Hello'); // O(1)
helloArray.push('world');
console.log(helloArray);
helloArray.pop(); // O(1)
console.log(helloArray);
helloArray.push('Deno');
helloArray.push('!');
console.log(helloArray);
console.log('At index 2:', helloArray.get(2));
// -------------------------------------------
let sokka = new MyArray<string>();
sokka.push('s');
sokka.push('o');
sokka.push('c');
sokka.push('k');
sokka.push('a');
console.log(sokka);
console.log('Element deleted:', sokka.deleteIndex(2)); // O(n)
console.log(sokka);
sokka.insertItemAtIndex(2, 'k'); // O(n)
console.log(sokka);
// RUN: deno run Data-Structures/Arrays/Implementation.ts
}
// --------------------------- Terminal Output: ---------------------------
// MyArray { length: 2, data: { 0: "Hello", 1: "world" } }
// MyArray { length: 1, data: { 0: "Hello" } }
// MyArray { length: 3, data: { 0: "Hello", 1: "Deno", 2: "!" } }
// At index 2: !
// MyArray { length: 5, data: { 0: "s", 1: "o", 2: "c", 3: "k", 4: "a" } }
// Element deleted: c
// MyArray { length: 4, data: { 0: "s", 1: "o", 2: "k", 3: "a" } }
// MyArray { length: 5, data: { 0: "s", 1: "o", 2: "k", 3: "k", 4: "a" } }
================================================
FILE: Data-Structures/Graphs/SimpleGraph.ts
================================================
type StrIndexedObject = { [index: string]: Set<string> };
export default class SimpleGraph {
private numberOfNodes: number;
private adjacentList: StrIndexedObject;
constructor() {
this.numberOfNodes = 0;
this.adjacentList = Object.create({});
}
public getNodeCount(): number {
return this.numberOfNodes;
}
public addVertex(node: string) {
this.adjacentList[node] = new Set<string>();
++this.numberOfNodes;
}
public addEdge(node1: string, node2: string) {
// Undirected, unweighted graph
this.adjacentList[node1].add(node2);
this.adjacentList[node2].add(node1);
}
public toString(): string {
const allNodes = Object.keys(this.adjacentList);
let representation: string = "";
for (let node of allNodes) {
let nodeConnections = this.adjacentList[node];
let vertex;
let count = 0;
let connections = " { ";
for (vertex of nodeConnections) {
connections += vertex + (count < nodeConnections.size-1 ? ", ": " ");
++count;
}
representation += (node + "-->" + connections + '}\n');
}
return representation;
}
}
function printGraph(graph: SimpleGraph) {
console.log(graph.toString());
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
let simpleGraph = new SimpleGraph();
simpleGraph.addVertex("0");
simpleGraph.addVertex("1");
simpleGraph.addVertex("2");
simpleGraph.addVertex("3");
simpleGraph.addVertex("4");
simpleGraph.addVertex("5");
simpleGraph.addVertex("6");
simpleGraph.addEdge("3", "1");
simpleGraph.addEdge("3", "4");
simpleGraph.addEdge("4", "2");
simpleGraph.addEdge("4", "5");
simpleGraph.addEdge("1", "2");
simpleGraph.addEdge("1", "0");
simpleGraph.addEdge("0", "2");
simpleGraph.addEdge("6", "5");
printGraph(simpleGraph);
// RUN: deno run Data-Structures/Graphs/Graph.ts
}
// --------------------------- Terminal Output: ---------------------------
// 0--> { 1, 2 }
// 1--> { 3, 2, 0 }
// 2--> { 4, 1, 0 }
// 3--> { 1, 4 }
// 4--> { 3, 2, 5 }
// 5--> { 4, 6 }
// 6--> { 5 }
================================================
FILE: Data-Structures/Hash-Tables/HashTable.ts
================================================
export class HashTable {
private size: number;
private data: Array<Array<any>>;
constructor(numBuckets: number) {
this.size = numBuckets;
this.data = new Array(numBuckets);
}
public insert(key: string, value: any): void {
let address = this._hash(key);
if (!this.data[address]) {
this.data[address] = [];
}
this.data[address].push([key,value]);
}
public get(key: string): any {
let address = this._hash(key);
const currentBucket: any[] = this.data[address];
if (currentBucket.length) {
for(let item of currentBucket) {
if (item[0] === key) return item[1];
}
}
return undefined;
}
public keys(): string[] {
const keysArray = new Array<string>();
// Loop through all buckets
for (let i=0; i < this.data.length; ++i) {
// If bucket has item(s)
if (this.data[i]) {
// Handle Collisions: Grab all keys from bucket
// (incl. multiple items)
for(let item of this.data[i]) {
keysArray.push(item[0]);
}
}
}
return keysArray;
}
public values(): string[] {
const valuesArray = new Array<string>();
for (let i=0; i < this.data.length; ++i) {
if (this.data[i]) {
for(let item of this.data[i]) {
valuesArray.push(item[1]);
}
}
}
return valuesArray;
}
public getSize(): number {
return this.size;
}
private _hash(key: string) {
let hash = 0;
for (let i=0; i < key.length; ++i) {
hash = (hash + key.charCodeAt(i) * i)
% this.data.length;
}
return hash;
}
public testHashFunction() {
console.log(this._hash('grapes'));
console.log(this._hash('grapess'));
console.log(this._hash('grapes'));
}
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
const hashTable = new HashTable(16);
// hashTable.testHashFunction();
hashTable.insert('grapes', 27); // Θ(1)
hashTable.insert('apples', 6);
hashTable.insert('tangerines', 12);
console.log('apples:', hashTable.get('apples'));
console.log('grapes:', hashTable.get('grapes'));
console.log(hashTable.keys());
console.log(hashTable.values());
// RUN: deno run Data-Structures/Hash-Tables/Implementation.ts
}
================================================
FILE: Data-Structures/Linked-Lists/DoublyLinkedList.ts
================================================
import Node from './DoublyNode.ts';
export default class DoublyLinkedList<T> {
private head: Node<T> | null;
private tail: Node<T> | null;
private length: number;
constructor() {
this.head = null;
this.tail = null;
this.length = 0;
}
public getLength(): number {
return this.length;
}
public isEmpty(): boolean {
return this.length === 0;
}
public append(value: T, demo?: boolean): boolean {
const newNode = new Node(value);
if (!this.tail) {
this.head = newNode;
this.tail = newNode;
}
else {
newNode.setPrevious(this.tail);
this.tail.setNext(newNode);
this.tail = this.tail.getNext();
}
++this.length;
if (demo) {
console.log('--------- Appending', value, 'at index', this.length-1);
console.log(this.toString());
}
return true;
}
public prepend(value: T, demo?: boolean): boolean {
const newNode = new Node(value);
if (!this.head) {
this.head = newNode;
this.tail = newNode;
} else {
newNode.setNext(this.head);
this.head.setPrevious(newNode);
this.head = newNode;
}
++this.length;
if (demo) {
console.log('--------- Prepending', value, '---------');
console.log(this.toString());
}
return true;
}
public insert(value: T, atIndex: number, demo?: boolean): boolean | null {
if (atIndex < 0 || atIndex > this.length) return null;
if (atIndex === 0) {
this.prepend(value, demo);
return true;
}
if (atIndex === this.length) {
this.append(value, demo);
return true;
}
const newNode = new Node(value);
const leader = this._traverseToNode(atIndex-1);
if (!leader) return false;
const follower = leader.getNext();
newNode.setPrevious(leader);
newNode.setNext(follower);
leader.setNext(newNode);
follower.setPrevious(newNode);
++this.length;
if (demo) {
console.log('--------- Inserting', value, 'at index', atIndex);
console.log(this.toString());
}
return true;
}
public getValueAtIndex(index: number): T | null {
if (index > this.length-1 || index < 0) return null; // Validate input
if (this.length === 0 || !this.head || !this.tail) return null; // Verify that list is not empty
if (index === this.length-1) return this.tail.getValue(); // Optimization when retrieving last element
let targetNode = this._traverseToNode(index);
return targetNode?.getValue() || null;
}
/**
* Find the index of the desired element if it exists.
* WARNING: Usable only for trees of primitive types, i.e. number, string
* @param value Value to search for, i.e. desired element
* @returns Numerical index of element position
*/
public searchFor(value: T): number | null {
if (this.length === 0 || !this.head) return null;
let currentNode = this.head;
for (let i=0; !!currentNode; ++i) {
if (currentNode.getValue()===value) return i; // Value matches, so return index
currentNode = currentNode.getNext(); // Otherwise, continue searching
}
return null;
}
/**
* Remove all nodes from list. Constant Time O(1)
*/
public empty(nestedCall?: boolean): boolean {
this.head = null;
this.tail = null;
this.length = nestedCall ? 1 : 0;
return true;
}
public removeElementAtIndex(index: number, demo?: boolean): T | null {
if (index > this.length-1 || index < 0) return null;
if (this.length === 0 || !this.head) return null;
let value = null;
if (index===0) {
value = this.head.getValue();
if (this.length > 1) {
const newHead = this.head.getNext();
newHead.setPrevious(null);
this.head.setNext(null);
this.head = newHead;
} else {
this.empty(true);
}
}
else {
let leader = this._traverseToNode(index-1);
const deletedNode = leader?.getNext();
value = deletedNode.getValue();
leader?.setNext(leader.getNext().getNext());
leader?.getNext().setPrevious(leader);
deletedNode.setNext(null);
deletedNode.setPrevious(null);
}
--this.length;
if (demo) {
console.log('Removing element at index', index + ':', JSON.stringify(value));
}
return value;
}
private _traverseToNode(index: number): Node<T> | null {
if (!this.head || !this.tail) return null;
let currentNode: Node<T>;
if (index < this.length/2) {
currentNode = this.head;
for (let i=0; i<index; ++i) {
currentNode = currentNode.getNext();
}
} else {
currentNode = this.tail;
for (let i=this.length-1; i>index; --i) {
currentNode = currentNode.getPrevious();
}
}
return currentNode;
}
public toString(nodesPerGroup?: number): string {
if (this.length === 0 || !this.head) {
return "";
}
nodesPerGroup = nodesPerGroup ? nodesPerGroup : 6;
const LABEL_HEAD = 'HEAD';
const LABEL_TAIL = 'TAIL';
let listAsString: string = `--- Node Count: ${this.length}\n`;
let currentNode: Node<any> = this.head;
for (let i=0; i < this.length; ++i) {
listAsString += `${Array(i%nodesPerGroup).fill('\t').join('')} ${i===0 ? LABEL_HEAD : i} ${currentNode} ${i===this.length-1 ? LABEL_TAIL : ''}\n`;
if (currentNode.hasNext()) {
currentNode = currentNode.getNext();
}
}
return listAsString;
}
}
function printLinkedList(linkedList: DoublyLinkedList<any>): void {
if (linkedList.isEmpty()) {
console.log('Empty linked list -_-');
return;
}
console.log(linkedList.toString());
}
function printSearchFor(value: any, linkedList: DoublyLinkedList<any>): void {
console.log(JSON.stringify(value), 'found at index:', linkedList.searchFor(value));
}
function printGetValueAtIndex(index: number, linkedList: DoublyLinkedList<any>) {
console.log('Element at index', index +':', linkedList.getValueAtIndex(index));
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
const ATLA = new DoublyLinkedList<string>();
ATLA.append('Sokka');
ATLA.append('Katara');
ATLA.prepend('Appa');
printLinkedList(ATLA);
ATLA.insert('Aang', 2, true);
ATLA.insert('Zuko', 1);
ATLA.insert('Iroh', 5, true);
ATLA.insert('Azula', 0, true);
printSearchFor('Iroh', ATLA);
printSearchFor('Sok', ATLA);
printSearchFor('Sokka', ATLA);
printSearchFor('Appa', ATLA);
printSearchFor('Zuko', ATLA);
printGetValueAtIndex(1, ATLA);
printGetValueAtIndex(6, ATLA);
console.log('----------------------------------');
ATLA.removeElementAtIndex(1, true);
printLinkedList(ATLA);
ATLA.removeElementAtIndex(0, true);
printLinkedList(ATLA);
ATLA.removeElementAtIndex(2, true);
printLinkedList(ATLA);
ATLA.removeElementAtIndex(2, true);
printLinkedList(ATLA);
ATLA.removeElementAtIndex(1, true);
ATLA.removeElementAtIndex(0, true);
ATLA.removeElementAtIndex(1, true);
ATLA.removeElementAtIndex(0, true);
printLinkedList(ATLA);
console.log('----------------------------------');
console.log();
ATLA.insert('Katara', 0, true);
ATLA.append('Aang');
printLinkedList(ATLA);
// RUN: deno run Data-Structures/Linked-Lists/DoublyLinkedList.ts
}
// --------------------------- Terminal Output: ---------------------------
// --- Node Count: 3
// HEAD { value: "Appa", next: true, previous: false }
// 1 { value: "Sokka", next: true, previous: true }
// 2 { value: "Katara", next: false, previous: true } TAIL
//
// --------- Inserting Aang at index 2
// --- Node Count: 4
// HEAD { value: "Appa", next: true, previous: false }
// 1 { value: "Sokka", next: true, previous: true }
// 2 { value: "Aang", next: true, previous: true }
// 3 { value: "Katara", next: false, previous: true } TAIL
//
// --------- Appending Iroh at index 5
// --- Node Count: 6
// HEAD { value: "Appa", next: true, previous: false }
// 1 { value: "Zuko", next: true, previous: true }
// 2 { value: "Sokka", next: true, previous: true }
// 3 { value: "Aang", next: true, previous: true }
// 4 { value: "Katara", next: true, previous: true }
// 5 { value: "Iroh", next: false, previous: true } TAIL
//
// --------- Prepending Azula ---------
// --- Node Count: 7
// HEAD { value: "Azula", next: true, previous: false }
// 1 { value: "Appa", next: true, previous: true }
// 2 { value: "Zuko", next: true, previous: true }
// 3 { value: "Sokka", next: true, previous: true }
// 4 { value: "Aang", next: true, previous: true }
// 5 { value: "Katara", next: true, previous: true }
// 6 { value: "Iroh", next: false, previous: true } TAIL
//
// "Iroh" found at index: 6
// "Sok" found at index: null
// "Sokka" found at index: 3
// "Appa" found at index: 1
// "Zuko" found at index: 2
// Element at index 1: Appa
// Element at index 6: Iroh
// ----------------------------------
// Removing element at index 1: "Appa"
// --- Node Count: 6
// HEAD { value: "Azula", next: true, previous: false }
// 1 { value: "Zuko", next: true, previous: true }
// 2 { value: "Sokka", next: true, previous: true }
// 3 { value: "Aang", next: true, previous: true }
// 4 { value: "Katara", next: true, previous: true }
// 5 { value: "Iroh", next: false, previous: true } TAIL
//
// Removing element at index 0: "Azula"
// --- Node Count: 5
// HEAD { value: "Zuko", next: true, previous: false }
// 1 { value: "Sokka", next: true, previous: true }
// 2 { value: "Aang", next: true, previous: true }
// 3 { value: "Katara", next: true, previous: true }
// 4 { value: "Iroh", next: false, previous: true } TAIL
//
// Removing element at index 2: "Aang"
// --- Node Count: 4
// HEAD { value: "Zuko", next: true, previous: false }
// 1 { value: "Sokka", next: true, previous: true }
// 2 { value: "Katara", next: true, previous: true }
// 3 { value: "Iroh", next: false, previous: true } TAIL
//
// Removing element at index 2: "Katara"
// --- Node Count: 3
// HEAD { value: "Zuko", next: true, previous: false }
// 1 { value: "Sokka", next: true, previous: true }
// 2 { value: "Iroh", next: false, previous: true } TAIL
//
// Removing element at index 1: "Sokka"
// Removing element at index 0: "Zuko"
// Removing element at index 0: "Iroh"
// Empty linked list -_-
// ----------------------------------
//
// --------- Prepending Katara ---------
// --- Node Count: 1
// HEAD { value: "Katara", next: false, previous: false } TAIL
//
// --- Node Count: 2
// HEAD { value: "Katara", next: true, previous: false }
// 1 { value: "Aang", next: false, previous: true } TAIL
================================================
FILE: Data-Structures/Linked-Lists/DoublyNode.ts
================================================
export default class DoublyLLNode<T> {
private value: T;
private next: DoublyLLNode<T> | null;
private previous: DoublyLLNode<T> | null;
constructor(value: T) {
this.value = value;
this.next = null;
this.previous = null;
}
public setValue(value: T) {
this.value = value;
}
public setNext(node: DoublyLLNode<T> | null) {
this.next = node;
}
public setPrevious(node: DoublyLLNode<T> | null) {
this.previous = node;
}
public getValue(): T {
return this.value;
}
public getNext(): DoublyLLNode<T> | any {
return this.next;
}
public getPrevious(): DoublyLLNode<T> | any {
return this.previous;
}
public hasNext(): boolean {
return !!this.next;
}
public hasPrevious(): boolean {
return !!this.previous;
}
public toString(): string {
return `{ value: ${JSON.stringify(this.value)}, next: ${!!this.next}, previous: ${!!this.previous} }`;
}
}
================================================
FILE: Data-Structures/Linked-Lists/LinkedList.ts
================================================
import Node from './SinglyNode.ts';
export default class LinkedList<T> {
private head: Node<T> | null;
private tail: Node<T> | null;
private length: number;
constructor() {
this.head = null;
this.tail = null;
this.length = 0;
}
public getLength(): number {
return this.length;
}
public getHeadValue(): T | any {
return this.head?.getValue();
}
public getTailValue(): T | any {
return this.tail?.getValue();
}
public isEmpty(): boolean {
return this.length === 0;
}
/**
* Remove all nodes from list. Constant Time O(1)
*/
public empty(): boolean {
this.head = null;
this.tail = null;
this.length = 0;
return true;
}
public append(value: T): boolean {
const newNode = new Node(value);
if (!this.tail) {
this.head = newNode;
this.tail = newNode;
}
else {
this.tail.setNext(newNode);
this.tail = this.tail.getNext();
}
++this.length;
return true;
}
public prepend(value: T): boolean {
const newNode = new Node(value);
if (!this.head) {
this.head = newNode;
this.tail = newNode;
} else {
newNode.setNext(this.head);
this.head = newNode;
}
++this.length;
return true;
}
public insert(value: T, atIndex: number): boolean | null {
if (atIndex < 0 || atIndex > this.length) return null;
if (!this.head) {
this.prepend(value);
return true;
}
if (atIndex === this.length) {
this.append(value);
return true;
}
const newNode = new Node(value);
let currentNode = this._traverseToNode(atIndex-1);
newNode.setNext(currentNode?.getNext());
currentNode?.setNext(newNode);
++this.length;
return true;
}
public removeElementAtIndex(index: number): T | null {
if (index > this.length-1 || index < 0) return null;
if (this.length === 0 || !this.head) return null;
let value = null;
if (index===0) {
value = this.head.getValue();
this.head = this.head.getNext(); // Manipulate pointers to mark deleted Node for garbage collection
}
else {
let leader = this._traverseToNode(index-1);
value = leader?.getNext().getValue();
leader?.setNext(leader.getNext().getNext()); // Manipulate pointers to mark deleted Node for garbage collection
}
--this.length; // Decrement length
return value;
}
public getValueAtIndex(index: number): T | null {
if (index > this.length-1 || index < 0) return null; // Validate input
if (this.length === 0 || !this.head || !this.tail) return null; // Verify that list is not empty
if (index === this.length-1) return this.tail.getValue(); // Optimization when retrieving last element
let targetNode = this._traverseToNode(index);
return targetNode?.getValue() || null;
}
/**
* Find the index of the desired element if it exists.
* WARNING: Usable only for trees of primitive types, i.e. number, string
* @param value Value to search for, i.e. desired element
* @returns Numerical index of element position
*/
public searchFor(value: T): number | null {
if (this.length === 0 || !this.head) return null;
let currentNode = this.head;
for (let i=0; !!currentNode; ++i) {
if (currentNode.getValue()===value) return i; // Value matches, so return index
currentNode = currentNode.getNext(); // Otherwise, continue searching
}
return null;
}
private _traverseToNode(index: number): Node<T> | null {
if (!this.head) return null;
let currentNode = this.head;
for (let i=0; i<index; ++i) {
currentNode = currentNode.getNext();
}
return currentNode;
}
public reverse(): boolean {
if (this.length < 2 || !this.head || !this.tail) return false;
this.tail = this.head; // Current head will become the new tail
let first = this.head;
let second = first.getNext();
let tempNode; // Will be the third sequential node in deletion sequence
// Travel up the tree while the second node is present, i.e. not null
while(second) {
tempNode = second.getNext();
second.setNext(first);
first = second;
second = tempNode;
}
this.tail.setNext(null);
this.head = first;
return true;
}
public toArray(): Array<T> | any {
if (this.length <= 0) return null;
const array = new Array<T>(this.length);
let currentNode = this.head;
for (let i=0; !!currentNode; ++i) {
array[i] = currentNode.getValue();
currentNode = currentNode.getNext();
}
return array;
}
public toString(nodesPerGroup?: number): string {
if (this.length === 0 || !this.head) {
return "";
}
nodesPerGroup = nodesPerGroup ? nodesPerGroup : 6;
const LABEL_HEAD = 'HEAD';
const LABEL_TAIL = 'TAIL';
let listAsString: string = `--- Node Count: ${this.length}\n`;
let currentNode: Node<any> = this.head;
for (let i=0; i < this.length; ++i) {
listAsString += `${Array(i%nodesPerGroup).fill('\t').join('')} ${i===0 ? LABEL_HEAD : i} ${currentNode} ${i===this.length-1 ? LABEL_TAIL : ''}\n`;
if (currentNode.hasNext()) {
currentNode = currentNode.getNext();
}
}
return listAsString;
}
}
function printLinkedList(linkedList: LinkedList<any>): void {
if (linkedList.isEmpty()) {
console.log('Empty linked list -_-');
return;
}
console.log(linkedList.toString());
}
function printSearchFor(value: any, linkedList: LinkedList<any>): void {
console.log(JSON.stringify(value), 'found at index:', linkedList.searchFor(value));
}
function printGetValueAtIndex(index: number, linkedList: LinkedList<any>) {
console.log('Element at index', index +':', linkedList.getValueAtIndex(index));
}
function printRemoveIndex(index: number, linkedList: LinkedList<any>) {
console.log('Removing element at index', index + ':', JSON.stringify(linkedList.removeElementAtIndex(index)));
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
const ATLA = new LinkedList<string>();
ATLA.append('Sokka');
ATLA.append('Katara');
ATLA.prepend('Appa');
printLinkedList(ATLA);
ATLA.insert('Aang', 2);
ATLA.insert('Zuko', 1);
ATLA.insert('Iroh', 4);
printLinkedList(ATLA);
printSearchFor('Iroh', ATLA);
printSearchFor('Sok', ATLA);
printSearchFor('Sokka', ATLA);
printSearchFor('Appa', ATLA);
printSearchFor('Zuko', ATLA);
printGetValueAtIndex(2, ATLA);
printGetValueAtIndex(5, ATLA);
console.log('------------ Reversing List ------------');
ATLA.reverse();
printLinkedList(ATLA);
console.log('----------------------------------');
printRemoveIndex(1, ATLA);
printLinkedList(ATLA);
printRemoveIndex(0, ATLA);
printLinkedList(ATLA);
printRemoveIndex(2, ATLA);
printLinkedList(ATLA);
printRemoveIndex(2, ATLA);
printLinkedList(ATLA);
printRemoveIndex(1, ATLA);
printRemoveIndex(0, ATLA);
printLinkedList(ATLA);
console.log('----------------------------------');
ATLA.insert('Katara', 0);
printLinkedList(ATLA);
ATLA.append('Aang');
printLinkedList(ATLA);
console.log('------------ Reversing List ------------');
ATLA.reverse();
printLinkedList(ATLA);
// RUN: deno run Data-Structures/Linked-Lists/LinkedList.ts
}
// --------------------------- Terminal Output: ---------------------------
// --- Node Count: 3
// HEAD { value: "Appa", next: true }
// 1 { value: "Sokka", next: true }
// 2 { value: "Katara", next: false } TAIL
//
// --- Node Count: 6
// HEAD { value: "Appa", next: true }
// 1 { value: "Zuko", next: true }
// 2 { value: "Sokka", next: true }
// 3 { value: "Aang", next: true }
// 4 { value: "Iroh", next: true }
// 5 { value: "Katara", next: false } TAIL
//
// "Iroh" found at index: 4
// "Sok" found at index: null
// "Sokka" found at index: 2
// "Appa" found at index: 0
// "Zuko" found at index: 1
// Element at index 2: Sokka
// Element at index 5: Katara
// ------------ Reversing List ------------
// --- Node Count: 6
// HEAD { value: "Katara", next: true }
// 1 { value: "Iroh", next: true }
// 2 { value: "Aang", next: true }
// 3 { value: "Sokka", next: true }
// 4 { value: "Zuko", next: true }
// 5 { value: "Appa", next: false } TAIL
//
// ----------------------------------
// Removing element at index 1: "Iroh"
// --- Node Count: 5
// HEAD { value: "Katara", next: true }
// 1 { value: "Aang", next: true }
// 2 { value: "Sokka", next: true }
// 3 { value: "Zuko", next: true }
// 4 { value: "Appa", next: false } TAIL
//
// Removing element at index 0: "Katara"
// --- Node Count: 4
// HEAD { value: "Aang", next: true }
// 1 { value: "Sokka", next: true }
// 2 { value: "Zuko", next: true }
// 3 { value: "Appa", next: false } TAIL
//
// Removing element at index 2: "Zuko"
// --- Node Count: 3
// HEAD { value: "Aang", next: true }
// 1 { value: "Sokka", next: true }
// 2 { value: "Appa", next: false } TAIL
//
// Removing element at index 2: "Appa"
// --- Node Count: 2
// HEAD { value: "Aang", next: true }
// 1 { value: "Sokka", next: false } TAIL
//
// Removing element at index 1: "Sokka"
// Removing element at index 0: "Aang"
// Empty linked list -_-
// ----------------------------------
// --- Node Count: 1
// HEAD { value: "Katara", next: false } TAIL
//
// --- Node Count: 2
// HEAD { value: "Katara", next: true }
// 1 { value: "Aang", next: false } TAIL
//
// ------------ Reversing List ------------
// --- Node Count: 2
// HEAD { value: "Aang", next: true }
// 1 { value: "Katara", next: false } TAIL
================================================
FILE: Data-Structures/Linked-Lists/SinglyNode.ts
================================================
export default class LinkedListNode<T> {
private value: T;
private next: LinkedListNode<T> | null;
constructor(value: T) {
this.value = value;
this.next = null;
}
public setValue(value: T) {
this.value = value;
}
public setNext(nextNode: LinkedListNode<T> | null) {
this.next = nextNode;
}
public getValue(): T {
return this.value;
}
public getNext(): LinkedListNode<T> | any {
return this.next;
}
public hasNext(): boolean {
return !!this.next;
}
public toString(): string {
return `{ value: ${JSON.stringify(this.value)}, next: ${!!this.next} }`;
}
}
================================================
FILE: Data-Structures/README.md
================================================
# Data Structures
## Core
- [X] Arrays
- [X] Hash Tables
- [X] Stacks
- [X] Queues
- [X] Linked Lists
- [X] Trees
- [X] Binary Search Tree (BST)
- AVL Tree
- Red Black Tree
- Binary Heap
- Priority Queue
- Trie
- [X] Graphs
## Resources
- [The Data Structures Handbook](https://www.thedshandbook.com/ "DS Handbook")
- [Comprehensive List of Data Structures](https://en.wikipedia.org/wiki/List_of_data_structures "Wikipedia: DS List")
- [Visualizing Data Structures & Algorithms](https://visualgo.net/en)
### Foundations
- [Arrays vs Linked Lists: Youtube](https://youtu.be/DyG9S9nAlUM)
- [Linked List: VisuAlgo](https://visualgo.net/en/list)
### Graphs
- [The Internet Map](https://internet-map.net/)
- [Graphs: VisuAlgo](https://visualgo.net/en/graphds)
### Trees
- [Binary Search Tree: VisuAlgo](https://visualgo.net/bn/bst?slide=1)
- [Binary Heap: VisuAlgo](https://visualgo.net/en/heap)
- [AVL Tree Visualization](https://www.cs.usfca.edu/~galles/visualization/AVLtree.html)
- [Red-Black Tree Visualization](https://www.cs.usfca.edu/~galles/visualization/RedBlack.html)
- [Priority Queue Implementation: GeeksForGeeks](https://www.cs.usfca.edu/~galles/visualization/RedBlack.html)
- [Validate a BST: GeeksForGeeks](https://www.geeksforgeeks.org/a-program-to-check-if-a-binary-tree-is-bst-or-not/)
### Hash Tables
- [MD5 Hash Generator](http://www.miraclesalad.com/webtools/md5.php)
- [Hash Table Animation](https://www.cs.usfca.edu/~galles/visualization/OpenHash.html)
- [Hash Table | Wikipedia](https://en.wikipedia.org/wiki/Hash_table)
- [Associative Arrays | Wikipedia](https://en.wikipedia.org/wiki/Comparison_of_programming_languages_(associative_array) "Hash Tables (aka Associative Arrays)")
================================================
FILE: Data-Structures/Sequential/Queue.ts
================================================
import Node from '../Linked-Lists/SinglyNode.ts';
export default class Queue<T> {
private last: Node<T> | null;
private first: Node<T>| null;
private length: number;
constructor() {
this.last = null;
this.first = null;
this.length = 0;
}
public getLength(): number {
return this.length;
}
public isEmpty(): boolean {
return this.length === 0;
}
public peek(): T | null {
return this.first?.getValue() || null;
}
public enqueue(value: T): boolean {
const newNode = new Node(value);
if (!this.last) { // If empty queue, initialize
this.first = newNode;
this.last = newNode;
}
else {
this.last.setNext(newNode);
this.last = this.last.getNext();
}
++this.length;
return true;
}
public dequeue(): T | any {
if (!this.first) return null; // Edge case: Empty queue
if (this.length === 1) { // Edge case: Queue has 1 element, so a dequeue should reset the queue's state
this.last = null; // Challenge: What is the state of each 'class field' after a dequeue when 1 element was remaining?
}
const value = this.first.getValue();
this.first = this.first.getNext();
--this.length;
return value;
}
}
function printQueue(queue: Queue<any>) {
console.log(JSON.stringify(queue));
}
function printPeekQueue(queue: Queue<any>) {
console.log('Peeking... Found', JSON.stringify(queue.peek()));
}
function printDequeue(queue: Queue<any>) {
console.log('Dequeued:', JSON.stringify(queue.dequeue()));
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
const ATLA = new Queue<string>();
printPeekQueue(ATLA);
ATLA.enqueue('Sokka');
ATLA.enqueue('Katara');
printPeekQueue(ATLA);
ATLA.enqueue('Aang');
ATLA.enqueue('Appa');
printQueue(ATLA);
printDequeue(ATLA);
printDequeue(ATLA);
printDequeue(ATLA);
printQueue(ATLA);
printDequeue(ATLA);
printQueue(ATLA);
ATLA.enqueue('Zuko');
ATLA.enqueue('Iroh');
printQueue(ATLA);
// RUN: deno run Data-Structures/Sequential/Queue.ts
}
// --------------------------- Terminal Output: ---------------------------
// Peeking... Found null
// Peeking... Found "Sokka"
// {"last":{"value":"Appa","next":null},"first":{"value":"Sokka","next":{"value":"Katara","next":{"value":"Aang","next":{"value":"Appa","next":null}}}},"length":4}
// Dequeued: "Sokka"
// Dequeued: "Katara"
// Dequeued: "Aang"
// {"last":{"value":"Appa","next":null},"first":{"value":"Appa","next":null},"length":1}
// Dequeued: "Appa"
// {"last":null,"first":null,"length":0}
// {"last":{"value":"Iroh","next":null},"first":{"value":"Zuko","next":{"value":"Iroh","next":null}},"length":2}
================================================
FILE: Data-Structures/Sequential/Stack.ts
================================================
export default class Stack<T> {
private length: number;
private values: Array<T>;
constructor() {
this.length = 0;
this.values = new Array<T>();
}
public getLength(): number {
return this.length;
}
public isEmpty(): boolean {
return this.length === 0;
}
public peek(): T | null {
return this.values[this.length-1] || null;
}
public push(value: T): boolean {
this.values[this.length] = value;
++this.length;
return true;
}
public pop() {
const value = this.values[this.length-1];
delete this.values[this.length-1];
--this.length;
return value;
}
}
function printStack(stack: Stack<any>) {
console.log(JSON.stringify(stack));
}
function printPopStack(stack: Stack<any>) {
console.log('Popped:', stack.pop());
}
function printPeekStack(stack: Stack<any>) {
console.log('Peeking... Found', stack.peek());
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
const ATLA = new Stack<string>();
printPeekStack(ATLA);
ATLA.push('Sokka');
ATLA.push('Katara');
printPeekStack(ATLA);
ATLA.push('Aang');
ATLA.push('Appa');
printStack(ATLA);
printPopStack(ATLA);
printStack(ATLA);
printPopStack(ATLA);
printPopStack(ATLA);
printPopStack(ATLA);
printStack(ATLA);
ATLA.push('Zuko');
ATLA.push('Iroh');
printStack(ATLA);
// RUN: deno run Data-Structures/Sequential/Stack.ts
}
// --------------------------- Terminal Output: ---------------------------
// Peeking... Found null
// Peeking... Found Katara
// {"length":4,"values":["Sokka","Katara","Aang","Appa"]}
// Popped: Appa
// {"length":3,"values":["Sokka","Katara","Aang",null]}
// Popped: Aang
// Popped: Katara
// Popped: Sokka
// {"length":0,"values":[null,null,null,null]}
// {"length":2,"values":["Zuko","Iroh",null,null]}
================================================
FILE: Data-Structures/Sequential/StackLL.ts
================================================
import Node from '../Linked-Lists/SinglyNode.ts';
export default class StackLL<T> {
private top: Node<T> | null;
private bottom: Node<T> | null;
private length: number;
constructor() {
this.top = null;
this.bottom = null;
this.length = 0;
}
public getLength(): number {
return this.length;
}
public isEmpty(): boolean {
return this.length === 0;
}
public peek(): T | null {
return this.top?.getValue() || null;
}
public push(value: T): boolean {
const newNode = new Node<T>(value);
if (!this.top) { // If stack is empty, initialize
this.top = newNode;
this.bottom = newNode;
}
else { // Else manipulate pointers
newNode.setNext(this.top);
this.top = newNode;
}
/* Challenge (Alternate Else Clause):
* 1. How does the code below behave and why is it incorrect?
* 2. What are the consequences to time complexity?
*/
// else {
// this.top.setNext(newNode); // Else, set next node of LL to new value
// this.top = this.top.getNext(); // And move 'top' pointer forward
// }
++this.length; // Increment length
return true;
}
public pop(): T | null {
if (!this.top) return null; // If empty stack, return null
if (this.length === 1) {
this.bottom = null;
}
const value = this.top.getValue(); // Retrieve top value of stack
this.top = this.top.getNext(); // Move top pointer to next node
// On line 55, the reference to the top most node of the stack is lost
// The node is now floating in memory, waiting patiently for the garbage collector
--this.length;
return value;
}
}
function printStack(stack: StackLL<any>) {
console.log(JSON.stringify(stack));
}
function printPopStack(stack: StackLL<any>) {
console.log('Popped:', stack.pop());
}
function printPeekStack(stack: StackLL<any>) {
console.log('Peeking:', stack.peek());
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
const ATLA = new StackLL<string>();
printPeekStack(ATLA);
ATLA.push('Sokka');
ATLA.push('Katara');
printPeekStack(ATLA);
ATLA.push('Aang');
ATLA.push('Appa');
printStack(ATLA);
printPopStack(ATLA);
printStack(ATLA);
printPopStack(ATLA);
printPopStack(ATLA);
printPopStack(ATLA);
printStack(ATLA);
ATLA.push('Zuko');
ATLA.push('Iroh');
printStack(ATLA);
// RUN: deno run Data-Structures/Sequential/StackLL.ts
}
// --------------------------- Terminal Output: ---------------------------
// Peeking: null
// Peeking: Katara
// {"top":{"value":"Appa","next":{"value":"Aang","next":{"value":"Katara","next":{"value":"Sokka","next":null}}}},"bottom":{"value":"Sokka","next":null},"length":4}
// Popped: Appa
// {"top":{"value":"Aang","next":{"value":"Katara","next":{"value":"Sokka","next":null}}},"bottom":{"value":"Sokka","next":null},"length":3}
// Popped: Aang
// Popped: Katara
// Popped: Sokka
// {"top":null,"bottom":null,"length":0}
// {"top":{"value":"Iroh","next":{"value":"Zuko","next":null}},"bottom":{"value":"Zuko","next":null},"length":2}
================================================
FILE: Data-Structures/Trees/BinarySearchTree.test.ts
================================================
import { assertEquals, assertNotEquals } from '../../test_deps.ts';
import BinarySearchTree from './BinarySearchTree.ts';
//---------------------------------------------------------------------
// ---------- UNIT TESTS ----------
//---------------------------------------------------------------------
// RUN: deno test Data-Structures/Trees/BinarySearchTree.test.ts
Deno.test({
name: "Compare Trees 1",
fn() {
const tree1 = new BinarySearchTree();
tree1.insert(30);
tree1.insert(6);
tree1.insert(92)
const tree2 = new BinarySearchTree();
tree2.insert(30);
tree2.insert(92);
tree2.insert(6);
assertEquals(tree1.equalsQuantum(tree2), true);
}
})
Deno.test({
name: "Compare Trees 2",
fn() {
const tree1 = new BinarySearchTree();
tree1.insert(30);
tree1.insert(6);
tree1.insert(92)
const tree2 = new BinarySearchTree();
tree2.insert(30);
tree2.insert(6);
tree2.insert(91);
assertEquals(tree1.equalsQuantum(tree2), false);
}
})
================================================
FILE: Data-Structures/Trees/BinarySearchTree.ts
================================================
import BNode from './BinaryTreeNode.ts';
import Queue from '../Sequential/Queue.ts';
export default class BinarySearchTree {
public static traverse(node: BNode | null) {
if(node === null) return;
const tree = Object.create({});
tree.value = node.getValue();
tree.left = node.getLeft() === null ? null : this.traverse(node.getLeft());
tree.right = node.getRight() === null ? null : this.traverse(node.getRight());
return tree;
}
// ------------------- Instance Code Starts Here -------------------
private root: BNode | null;
constructor() {
this.root = null;
}
public getRoot(): BNode | null {
return this.root;
}
public insert(value: number) {
// If empty tree, create root
if(this.root === null) {
this.root = new BNode(value);
return this.root;
}
// Otherwise, traverse tree to find correct insert location
let currentNode: BNode = this.root;
while(true) {
// Value is smaller than current node
if (value < currentNode.getValue()) {
if(!currentNode.getLeft()) { // If no left node on currentNode
currentNode.setLeft(new BNode(value)); // Create left node with value
return this;
} else {
currentNode = currentNode.getLeft(); // Otherwise, go into existing left node
continue; // Small optimization
}
}
// Value is greater than or equal to current node
if (value >= currentNode.getValue()) {
if(!currentNode.getRight()) { // If no right node on currentNode
currentNode.setRight(new BNode(value)); // Create right node with value
return this;
} else {
currentNode = currentNode.getRight(); // Otherwise, go into the existing right node
continue; // Small optimization
}
}
}
}
public lookup(value: number): BNode | null {
let currentNode: BNode;
if(!!this.root) {
currentNode = this.root;
} else {
return null;
}
while(true) {
// We found our value!
if (value === currentNode.getValue()) {
return currentNode;
}
if (value < currentNode.getValue()) { // Value is smaller than current node
if(!!currentNode.getLeft()) { // If left child exists
currentNode = currentNode.getLeft(); // Move into left child
continue;
}
return null; // Otherwise No left child, value DNE
}
else { // Value is greater than current node
if(!!currentNode.getRight()) { // If right child exists
currentNode = currentNode.getRight(); // Move into right child
continue;
}
return null; // Otherwise no right child, value DNE
}
}
}
public remove(value: number): boolean {
let parentNode: BNode | null;
let currentNode: BNode;
if(!!this.root) {
currentNode = this.root;
parentNode = null;
} else {
return false;
}
while(true) {
if (value < currentNode.getValue()) {
parentNode = currentNode;
currentNode = currentNode.getLeft()
continue;
}
else if(value > currentNode.getValue()) {
parentNode = currentNode;
currentNode = currentNode.getRight();
continue;
}
else if(value === currentNode.getValue()){ // Found node to delete!
// Decision Tree for Deleting a Node
// Branch 1: No right child
if (!currentNode.getRight()) {
if (!parentNode) {
this.root = currentNode.getLeft();
}
else {
if (currentNode.getValue() < parentNode.getValue()) {
parentNode.setLeft(currentNode.getLeft());
}
else if (currentNode.getValue() > parentNode.getValue()) {
parentNode.setRight(currentNode.getLeft());
}
}
}
// Branch 2: Right child w/ no left child
else if (!currentNode.getRight().getLeft()) {
if (!parentNode) {
this.root = currentNode.getLeft();
} else {
currentNode.getRight().setLeft(currentNode.getLeft());
if (currentNode.getValue() < parentNode.getValue()) {
parentNode.setLeft(currentNode.getRight());
}
else if (currentNode.getValue() > parentNode.getValue()) {
parentNode.setRight(currentNode.getRight());
}
}
}
// Branch 3: Right child w/ left child
else {
// Find the right child's left most child
let leftmost = currentNode.getRight().getLeft();
let parentOfLeftmost = currentNode.getRight();
while(!!leftmost.getLeft()) {
parentOfLeftmost = leftmost;
leftmost = leftmost.getLeft();
}
// Parent's left subtree is now leftmost's right subtree
parentOfLeftmost.setLeft(leftmost.getRight());
leftmost.setLeft(currentNode.getLeft());
leftmost.setRight(currentNode.getRight());
if (!parentNode) {
this.root = leftmost;
}
else {
if (currentNode.getValue() < parentNode.getValue()) {
parentNode.setLeft(leftmost);
}
else if (currentNode.getValue() > parentNode.getValue()) {
parentNode.setRight(leftmost);
}
}
}
}
return true; // Node removal was a success!
}
}
public invertTree(): boolean {
if (!this.root) false;
this._invertNode(this.root);
return true;
}
private _invertNode(current: BNode | null) {
if (current === null) return;
this._swapChildren(current);
this._invertNode(current.getLeft());
this._invertNode(current.getRight());
}
private _swapChildren(node: BNode) {
const left = node.getLeft();
node.setLeft(node.getRight());
node.setRight(left);
}
public breadthFirstTraversal() {
if (!this.root) return false;
let currentNode = this.root;
let nodesTraversed = new Array();
const nodeQueue: Queue<BNode> = new Queue();
nodeQueue.enqueue(currentNode);
while (nodeQueue.getLength() > 0) {
currentNode = nodeQueue.dequeue();
nodesTraversed.push(currentNode.getValue());
if (currentNode.hasLeft()) nodeQueue.enqueue(currentNode.getLeft());
if (currentNode.hasRight()) nodeQueue.enqueue(currentNode.getRight());
}
return nodesTraversed;
}
public equalsQuantum(tree: BinarySearchTree): boolean {
return JSON.stringify(this) === JSON.stringify(tree);
}
}
function printNode(tree: BinarySearchTree, value: number): void {
const requestedNode = tree.lookup(value);
console.log('Find', value + ':', !!requestedNode ? JSON.stringify(requestedNode) : 'Node not found.');
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
const tree = new BinarySearchTree();
// 9
// 4 20
// 1 6 15 170
tree.insert(9);
tree.insert(4);
tree.insert(6);
tree.insert(20);
tree.insert(170);
tree.insert(15);
tree.insert(1);
console.log(tree.breadthFirstTraversal());
// console.log('Tree: ', JSON.stringify(BinarySearchTree.traverse(tree.getRoot())));
tree.remove(20);
printNode(tree, 4);
printNode(tree, 17);
printNode(tree, 40);
printNode(tree, 170);
console.log('Original Tree: ', JSON.stringify(BinarySearchTree.traverse(tree.getRoot())));
tree.invertTree();
console.log('Inverse Tree: ', JSON.stringify(BinarySearchTree.traverse(tree.getRoot())));
console.log(tree.breadthFirstTraversal());
// RUN: deno run Data-Structures/Trees/BinarySearchTree.ts
}
// --------------------------- Terminal Output: ---------------------------
// [
// 9, 4, 20, 1,
// 6, 15, 170
// ]
// Tree: {"value":9,"left":{"value":4,"left":{"value":1,"left":null,"right":null},"right":{"value":6,"left":null,"right":null}},"right":{"value":20,"left":{"value":15,"left":null,"right":null},"right":{"value":170,"left":null,"right":null}}}
// Find 4: {"value":4,"left":{"value":1,"left":null,"right":null},"right":{"value":6,"left":null,"right":null}}
// Find 17: Node not found.
// Find 40: Node not found.
// Find 170: {"value":170,"left":{"value":15,"left":null,"right":null},"right":null}
// Original Tree: {"value":9,"left":{"value":4,"left":{"value":1,"left":null,"right":null},"right":{"value":6,"left":null,"right":null}},"right":{"value":170,"left":{"value":15,"left":null,"right":null},"right":null}}
// Inverse Tree: {"value":9,"left":{"value":170,"left":null,"right":{"value":15,"left":null,"right":null}},"right":{"value":4,"left":{"value":6,"left":null,"right":null},"right":{"value":1,"left":null,"right":null}}}
// [ 9, 170, 4, 15, 6, 1 ]
================================================
FILE: Data-Structures/Trees/BinaryTreeNode.ts
================================================
export default class BinaryTreeNode {
private value: number;
private left: BinaryTreeNode | null;
private right: BinaryTreeNode | null;
constructor(value: number) {
this.value = value;
this.left = null;
this.right = null;
}
public setValue(value: number) {
this.value = value;
}
public setLeft(binaryTreeNode: BinaryTreeNode) {
this.left = binaryTreeNode;
}
public setRight(binaryTreeNode: BinaryTreeNode) {
this.right = binaryTreeNode;
}
public getValue(): number {
return this.value;
}
public getLeft(): BinaryTreeNode | any {
return this.left;
}
public getRight(): BinaryTreeNode | any {
return this.right;
}
public hasLeft(): boolean {
if (!!this.left) return true;
return false;
}
public hasRight(): boolean {
if (!!this.right) return true;
return false;
}
}
================================================
FILE: Playground/Demos/Classes_101.ts
================================================
// RUN: deno run Playground/Demos/Classes_101.ts
class Bender {
protected name: string;
protected isFemale: boolean;
protected element: string;
constructor(name: string, isFemale: boolean, element: string) {
this.name = name;
this.isFemale = isFemale;
this.element = element;
// console.log('bender', this);
}
public introduce() {
console.log(`"Hi, I am ${this.name}. I'm from the ${this.element} nation!"`);
}
}
class EarthBender extends Bender {
protected specialty?: string;
constructor(name: string, isFemale: boolean, specialty?: string) {
super(name, isFemale, 'Earth');
this.specialty = specialty;
// console.log('EarthBender', this);
}
public earthbend() {
console.log(`${this.name} lifts the ground beneath ${this.isFemale ? 'her' : 'him'}!`);
}
}
const toph = new EarthBender('Toph', true, 'metal');
const bumi = new EarthBender('Bumi', false);
toph.introduce();
toph.earthbend();
bumi.introduce();
bumi.earthbend();
================================================
FILE: Playground/Demos/Objects_101.ts
================================================
// RUN: deno run Playground/Demos/Objects_101.ts
console.log('------------------------- Episode 1 -------------------------');
const episode1 = {
name: 'The Boy in the Iceberg',
location: ['Shipwreck', 'Southern Water Tribe', "Zuko's Ship"],
characters: ['Aang', 'Appa', 'Katara', 'Sokka', 'Iroh', 'Zuko'],
introduction: function() {
return "Water. Earth. Fire. Air. Long ago, the four nations lived together in harmony.";
}
};
console.log(episode1);
console.log('------------------------- Episode 2 -------------------------');
const episode2 = Object.create(episode1);
console.log(episode2); // While fields don't show on console,
console.log(episode2.name, '—', episode2['characters']); // they are still populated by passed in prototype.
console.log(episode2.introduction()); // Function also exists because episode1 used as prototype.
episode2.name = 'The Avatar Returns';
episode2['location'] = ['Southern Water Tribe', "Zuko's Ship"]; // Recommended assignment syntax
episode2['characters'] = ['Aang', 'Appa', 'Katara', 'Sokka', 'Iroh', 'Zuko'];
console.log(episode2);
console.log('------------------------- Episode 3 -------------------------');
const episode3 = Object.create({});
// console.log(episode3.introduction()); // Does not exist because didn't use episode1 prototype
episode3.name = 'The Southern Air Temple';
episode3['location'] = ['Earth Kingdom Harbor', 'Southern Air Temple']; // Recommended syntax
episode3[1] = 'The Air Temple is one of the most beautiful places in the world!'; // Can also use syntax for numerical index in object
console.log(episode3);
================================================
FILE: Playground/Interviews/HealthcareHM.ts
================================================
function findNumOccurrences(color: string, colorsArr: string[]): number {
let occurrences = 0;
for (let c of colorsArr) {
if (color === c) ++occurrences;
}
return occurrences;
}
console.log(findNumOccurrences("black", ["white", "red", "black", "green", "black", "red"]));
function unique(array: Array<number> | Array<string>): boolean {
const found = new Set();
for (let element of array) {
if (found.has(element)) return false;
else found.add(element);
}
return true;
}
console.log(unique([1,4,6,8,2]));
console.log(unique([1,4,6,8,4,2]));
// RUN: deno run Playground/Interviews/HealthcareHM.ts
================================================
FILE: Playground/Puzzles/AngryFrogs.test.ts
================================================
import { assertEquals } from '../../test_deps.ts';
import maxDistance from './AngryFrogs.ts';
// RUN: deno test Playground/Puzzles/AngryFrogs.test.ts
//---------------------------------------------------------------------
// ---------- UNIT TESTS ----------
//---------------------------------------------------------------------
Deno.test({
name: "[1,2,3,4,5] -> 4",
fn() {
let lilypadHeights = [1,2,3,4,5];
assertEquals(maxDistance(lilypadHeights), 4);
}
});
Deno.test({
name: "[5,7,3,1,2,3,4,6,2] -> 6",
fn() {
let lilypadHeights = [5,7,3,1,2,3,4,6,2];
assertEquals(maxDistance(lilypadHeights), 6);
}
});
================================================
FILE: Playground/Puzzles/AngryFrogs.ts
================================================
export default function maxDistance(lilypadHeights: number[]) {
Solution.initializeLilypadForest(lilypadHeights);
return Solution.findMaxDistance();
}
class Solution {
private static lilypadForest: number[];
static initializeLilypadForest(lilypadHeights: number[]) {
Solution.lilypadForest = lilypadHeights;
}
static findMaxDistance(): number {
let maxDistance = 0;
let distanceTraveledLeft, distanceTraveledRight, distanceTraveled;
for(let i=0; i < Solution.lilypadForest.length; ++i) {
// console.log("Lilypad", i);
distanceTraveledRight = Solution._travelRightFrom(i);
distanceTraveledLeft = Solution._travelLeftFrom(i);
distanceTraveled = distanceTraveledLeft + distanceTraveledRight;
// console.log(" Distance Traveled:", distanceTraveled)
if(distanceTraveled > maxDistance)
maxDistance = distanceTraveled;
// console.log(" Max Distance:", maxDistance)
}
return maxDistance;
}
private static _travelRightFrom(index: number): number {
for(let i=index; ; ++i) {
if(i+1 == Solution.lilypadForest.length ||
Solution.lilypadForest[i+1] < Solution.lilypadForest[i]) {
// console.log(" Traveled Right: ", i-index);
return i-index;
}
}
}
private static _travelLeftFrom(index: number): number {
for(let i=index; ; --i) {
if(i-1 < 0 || Solution.lilypadForest[i-1] < Solution.lilypadForest[i]) {
// console.log(" Traveled Left: ", index-i);
return index-i;
}
}
}
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
let forest1 = [5,7,3,1,2,3,4,6,2];
console.log("Forest 1: ", maxDistance(forest1));
// RUN: deno run Playground/Puzzles/AngryFrogs.ts
}
================================================
FILE: Playground/ZTM Challenges/Arrays/Compare_Arrays.test.ts
================================================
import { assertEquals, assertNotEquals } from "../../../test_deps.ts";
import { containsCommonItem } from "./Compare_Arrays.ts";
const array1 = ['a', 'b', 'c', 'x'];
const array2 = ['z', 'y', 'x'];
const array3 = ['z', 't', 'i'];
//---------------------------------------------------------------------
// ---------- UNIT TESTS ----------
//---------------------------------------------------------------------
// RUN: deno test Playground/Challenges/Arrays/Compare_Arrays.test.ts
Deno.test({
name: "Matching Elements 1",
fn() {
assertEquals(containsCommonItem(array1, array2) , true);
}
});
Deno.test({
name: "Matching Elements 2",
fn() {
assertEquals(containsCommonItem(array2, array3) , true);
}
});
Deno.test({
name: "No Matching 1",
fn() {
assertNotEquals(containsCommonItem(array1, array3) , true);
}
});
================================================
FILE: Playground/ZTM Challenges/Arrays/Compare_Arrays.ts
================================================
// Given 2 arrays, create a function that let's a user
// know (true/false) whether these two arrays contain any common items
//
// For Example:
// const array1 = ['a', 'b', 'c', 'x'];
// const array2 = ['z', 'y', 'i'];
// Should return false.
// -----------
// const array1 = ['a', 'b', 'c', 'x'];
// const array2 = ['z', 'y', 'x'];
// Should return true.
// Arrays have no size limit
// Return true or false
// Naive (Brute Force) Solution
function containsCommonItemBF(arr1: Array<string>, arr2: Array<string>): boolean {
for (let i=0; i < arr1.length; i++) { // O(a)
for (let j=0; j < arr2.length; j++) { // O(b)
if(arr1[i] === arr2[j]) // O(1)
return true;
}
}
return false;
}
// Time Efficient Solution
export function containsCommonItem(arr1: Array<string>, arr2: Array<string>): boolean {
// Iterate through first array and record seen items
let map = Object.create({});
for (let i=0; i < arr1.length; i++) { // O(a)
const currentItem = arr1[i];
if (!map[currentItem]) {
map[currentItem] = true;
}
}
// Iterate through second array and check the record
for (let i=0; i < arr2.length; i++) { // O(b)
if (map[arr2[i]]) return true;
}
return false;
}
// Works the same as time efficient solution
export function containsCommonItemSyntacticSugar(arr1: Array<string>, arr2: Array<string>): boolean {
return arr1.some(item => arr2.includes(item));
}
if (import.meta.main) {
const array1 = ['a', 'b', 'c', 'x'];
const array2 = ['z', 'y', 'x'];
const array3 = ['z', 'y', 'i'];
console.log(containsCommonItemBF(array1, array2)); // O(a*b)
console.log(containsCommonItemBF(array1, array3)); // O(a*b)
console.log(containsCommonItem(array1, array2)); // O(a+b)
console.log(containsCommonItem(array1, array3)); // O(a+b)
}
================================================
FILE: Playground/ZTM Challenges/Arrays/Merge_Sorted_Arrays.ts
================================================
// Challenge: Given two sorted numerical arrays,
// merge them into a sorted array
//
// Example:
// Input: [1,3,8,9] and [2,5,7]
// Output: [1,2,3,5,7,8,9]
function mergeSortedArrays(arr1: number[], arr2: number[]): Array<number> { // Time Complexity: O(a+b)
const largeSorted: number[] = [];
for(let i=0,j=0; i <= arr1.length && j <= arr2.length;) {
if (i === arr1.length && j === arr2.length) {
break;
}
if (i === arr1.length) {
largeSorted.push(arr2[j]);
++j;
continue;
}
if (j === arr2.length) {
largeSorted.push(arr1[i]);
++i;
continue;
}
if (arr1[i] < arr2[j]) {
largeSorted.push(arr1[i]);
++i;
} else {
largeSorted.push(arr2[j])
++j;
}
}
return largeSorted;
}
const arr1 = [1,3,8,9];
const arr2 = [2,5,7];
console.log(mergeSortedArrays(arr1, arr2)); // O(a+b)
console.log(mergeSortedArrays([4,6,30], [0,3,4,31])); // O(a+b)
console.log(mergeSortedArrays([2,4,8,16,32], [])); // O(a+b)
console.log(mergeSortedArrays([], [])); // O(a+b)
================================================
FILE: Playground/ZTM Challenges/Arrays/Reverse_String.ts
================================================
// Challenge: Reverse the characters of a string, preserving
// capitalization and spaces
//
// Example:
// Input — "Avatar the Last Airbender"
// Output — "rednebriA tsaL eht ratavA"
function reverseString(input: string): string {
let reversed: string[] = [];
if (input.length > 1) {
for (let i = input.length; i > 0; --i) {
reversed.push(input.charAt(i-1)); // input[i-1] will also work in JS
}
}
return reversed.join('');
}
function reverseWithJavascriptVoodoo(input: string): string {
return input.split('').reverse().join('');
}
const reverseWithMoreVoodoo = (str: string) => [...str].reverse().join('');
console.log(reverseString("ATLA"));
console.log(reverseString("Avatar the Last Airbender"));
================================================
FILE: Playground/ZTM Challenges/Arrays/Sum_Pair.ts
================================================
// Challenge: Given an array of unordered numbers and a sum,
// is there a pair of numbers which add up to the sum?
// Naive (Brute Force) Solution
function hasPairWithSumBF(arr: number[], sum: number): boolean {
for (var i = 0; i < arr.length - 1; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (arr[i] + arr[j] === sum) {
return true;
}
}
}
return false;
}
// Efficient Solution
function hasPairWithSum(arr: number[], sum: number) {
const mySet = new Set<number>();
for (let i = 0; i < arr.length; i++) {
if (mySet.has(arr[i])) {
return true;
}
mySet.add(sum - arr[i]);
}
return false;
}
console.log(hasPairWithSumBF([6, 4, 3, 2, 1, 7], 9)); // O(n^2)
console.log(hasPairWithSum([6, 4, 3, 2, 1, 7], 9)); // O(n)
console.log(hasPairWithSum([1,2,3,9], 8)); // O(n)
================================================
FILE: Playground/ZTM Challenges/Hash-Tables/Recurring_Symbol.test.ts
================================================
import { assertEquals } from "../../../test_deps.ts";
import {
firstRecurringNumber,
findFirstRecurring,
} from "./Recurring_Symbol.ts";
const array1 = [2, 5, 1, 2, 3, 5, 1, 2, 4];
const array2 = [2, 1, 1, 2, 3, 5, 1, 2, 4];
const array3 = [2, 3, 4, 5];
const array4 = [2, 5, 5, 2, 3, 5, 1, 2, 4];
const array5 = ["a", "z", "n", "z", "x", "g"];
//---------------------------------------------------------------------
// ---------- UNIT TESTS ----------
//---------------------------------------------------------------------
// RUN: deno test Playground/Challenges/Hash-Tables/Recurring_Symbol.test.ts
Deno.test({
name: "Recurring Character",
fn() {
// ["a", "z", "n", "z", "x", "g"];
assertEquals(findFirstRecurring(array5), "z");
}
});
Deno.test({
name: "Recurring Number 1",
fn() {
// [2, 5, 1, 2, 3, 5, 1, 2, 4]
assertEquals(firstRecurringNumber(array1), 2);
}
});
Deno.test({
name: "Recurring Number 2",
fn() {
// [2, 1, 1, 2, 3, 5, 1, 2, 4]
assertEquals(firstRecurringNumber(array2), 1);
}
});
Deno.test({
name: "Recurring Number 3",
fn() {
// [2, 3, 4, 5]
assertEquals(firstRecurringNumber(array3), undefined);
}
});
Deno.test({
name: "Recurring Number 4",
fn() {
// [2, 5, 5, 2, 3, 5, 1, 2, 4]
assertEquals(firstRecurringNumber(array4), 5);
}
});
================================================
FILE: Playground/ZTM Challenges/Hash-Tables/Recurring_Symbol.ts
================================================
// ---------- Google Interview Question ----------
// Given an array = [2,5,1,2,3,5,1,2,4]:
// It should return 2
// Given an array = [2,1,1,2,3,5,1,2,4]:
// It should return 1
// Given an array = [2,3,4,5]:
// It should return undefined
// Bonus... What if we had this:
// [2,5,5,2,3,5,1,2,4]
// Return 5 because the pairs are before 2,2
// Solution by CoffeelessProgrammer ---------------------------------------
/**
* Finds the first recurring element of a numerical array.
* @param {Array<number>} numArray
* @returns {number | undefined} First repeated number, or undefined if none
*/
export function firstRecurringNumber(numArray: number[]): number | undefined {
let seen = new Set<number>();
for (let i=0; i < numArray.length; ++i) {
if (seen.has(numArray[i])) {
return numArray[i];
}
seen.add(numArray[i]);
}
return undefined;
}
/**
* Finds the first recurring element of a numerical or string array.
* @param {Array<number> | Array<string>} arr
* @returns {number | string | undefined} First repeated symbol, or undefined if none
*/
export function findFirstRecurring(arr: number[] | string[]): number | string | undefined {
let seen = new Set();
for (let i=0; i < arr.length; ++i) {
if (seen.has(arr[i])) {
return arr[i];
}
seen.add(arr[i]);
}
return undefined;
}
================================================
FILE: Playground/ZTM Challenges/Josephus.ts
================================================
export default class Josephus {
private numberOfSoldiers: number;
private circleOfSoldiers: Array<boolean>;
private livingCount: number;
constructor(numSoldiers: number) {
this.numberOfSoldiers = numSoldiers > 1 ? numSoldiers : 2;
this.circleOfSoldiers = new Array(this.numberOfSoldiers).fill(true);
this.livingCount = this.numberOfSoldiers;
}
public setNumSoldiers(numSoldiers: number) {
this.numberOfSoldiers = numSoldiers;
this.reset();
}
public getNumSoldiers(): number {
return this.numberOfSoldiers;
}
public reset(): void {
this.circleOfSoldiers = new Array(this.numberOfSoldiers).fill(true);
this.livingCount = this.numberOfSoldiers;
}
public solveBF(): number {
if (this.numberOfSoldiers < 2) return 0;
let lastKnight: number = -1;
let dead = Array<number>();
for (let i=this._findThirdLiving(0); this.livingCount > 1; i = this._findThirdLiving(i)) {
this._markDead(i)
dead.push(i+1);
i = this._findNextLiving(i);
if (this.livingCount === 1) lastKnight = i;
}
this.reset();
return lastKnight;
}
public solveVisual(): number {
if (this.numberOfSoldiers < 2) return 0;
let lastKnight: number = -1;
console.log('\nThe Romans prepare to clear the caves.\n');
let dead = Array<number>();
for (let i=this._findThirdLiving(0); this.livingCount > 1; i = this._findThirdLiving(i)) {
this._markDead(i)
dead.push(i+1);
console.log('\tKnight', i+1, 'is slain.');
i = this._findNextLiving(i);
console.log('Knight', i+1, 'prepares to strike the next blow.')
if (this.livingCount === 1) {
console.log('But sees no one meet his gaze...');
lastKnight = i;
}
}
console.log('\nK'+(lastKnight+1), 'is the last knight standing.');
console.log('\nSlain knights:', dead.toString());
this.reset();
return lastKnight;
}
private _findNextLiving(index: number): number {
for (let i = (index+1)%this.numberOfSoldiers; this.livingCount>0; i = (i+1)%this.numberOfSoldiers) {
if (this.circleOfSoldiers[i] === true) return i;
}
return -1;
}
private _findThirdLiving(index: number): number {
let counter = 0;
for (let i = (index+1)%this.numberOfSoldiers; this.livingCount>1; i = (i+1)%this.numberOfSoldiers) {
if (this.circleOfSoldiers[i] === true) {
if (counter < 3) ++counter;
}
if (counter === 3) return i;
}
return -1;
}
private _markDead(index:number): number {
this.circleOfSoldiers[index] = false;
--this.livingCount;
return index;
}
}
function printJosephusSolution(circleOfKnights: Josephus) {
console.log('\nSolution for Circle of', circleOfKnights.getNumSoldiers(),'\n– Last Knight at Index:', circleOfKnights.solveBF());
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
const knights1 = new Josephus(-1);
knights1.solveVisual();
const knights2 = new Josephus(6);
knights2.solveVisual();
const knights3 = new Josephus(8);
knights3.solveVisual();
printJosephusSolution(knights3);
// RUN: deno run Playground/Challenges/Josephus.ts
}
// --------------------------- Terminal Output: ---------------------------
// The Romans prepare to clear the caves.
//
// Knight 2 is slain.
// Knight 1 prepares to strike the next blow.
// But sees no one meet his gaze...
//
// K1 is the last knight standing.
//
// Slain knights: 2
//
// The Romans prepare to clear the caves.
//
// Knight 4 is slain.
// Knight 5 prepares to strike the next blow.
// Knight 2 is slain.
// Knight 3 prepares to strike the next blow.
// Knight 1 is slain.
// Knight 3 prepares to strike the next blow.
// Knight 3 is slain.
// Knight 5 prepares to strike the next blow.
// Knight 6 is slain.
// Knight 5 prepares to strike the next blow.
// But sees no one meet his gaze...
//
// K5 is the last knight standing.
//
// Slain knights: 4,2,1,3,6
//
// The Romans prepare to clear the caves.
//
// Knight 4 is slain.
// Knight 5 prepares to strike the next blow.
// Knight 8 is slain.
// Knight 1 prepares to strike the next blow.
// Knight 5 is slain.
// Knight 6 prepares to strike the next blow.
// Knight 2 is slain.
// Knight 3 prepares to strike the next blow.
// Knight 1 is slain.
// Knight 3 prepares to strike the next blow.
// Knight 3 is slain.
// Knight 6 prepares to strike the next blow.
// Knight 7 is slain.
// Knight 6 prepares to strike the next blow.
// But sees no one meet his gaze...
//
// K6 is the last knight standing.
//
// Slain knights: 4,8,5,2,1,3,7
//
// Solution for Circle of 8
// – Last Knight at Index: 5
================================================
FILE: Playground/ZTM Challenges/Recursion/ReverseString.ts
================================================
function reverseStringRecursive(str: string): string {
if (str.length===0) return "";
return reverseStringRecursive(str.substring(1)) + str.charAt(0);
}
function printReverseString(str: string) {
console.log(str, '–>', reverseStringRecursive(str));
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
printReverseString("Hello World!");
printReverseString("C0mp!ex1tY");
printReverseString("Avatar: The Last Airbender");
// RUN: deno run Playground/Challenges/Recursion/ReverseString.ts
}
================================================
FILE: Playground/ZTM Challenges/StackifiedQueue.ts
================================================
import Stack from '../../Data-Structures/Sequential/Stack.ts';
// Ahhhhh! What a glorious day to do things just because we can! ^.^
class StackifiedQueue<T> {
private first: Stack<T>; // Stack with elements ordered first-on-top
private last: Stack<T>; // Stack with elements ordered last-on-top
private length: number;
constructor() {
this.first = new Stack();
this.last = new Stack();
this.length = 0;
}
public getlength(): number {
return this.length;
}
public isEmpty(): boolean {
return this.length === 0;
}
public enqueue(value: T): boolean {
// Transfer all items from first-on-top to last-on-top
this._populateLastOnTop();
// Add to end of line, i.e. push to last-on-top stack
this.last.push(value);
++this.length;
return true;
}
public dequeue(): T | null {
if(this.length === 0) return null;
this._populateFirstOnTop();
--this.length;
return this.first.pop();
}
public peek(): T | null {
if (this.length === 0) return null;
this._populateFirstOnTop();
return this.first.peek();
}
private _populateFirstOnTop(): void {
if (this.first.getLength() > 0) return;
for (let i = 0; i < this.length; ++i) {
this.first.push(this.last.pop());
}
}
private _populateLastOnTop(): void {
if (this.last.getLength() > 0) return;
for (let i = 0; i < this.length; ++i) {
this.last.push(this.first.pop());
}
}
}
function printQueue(queue: StackifiedQueue<any>) {
console.log(JSON.stringify(queue));
}
function printPeekQueue(queue: StackifiedQueue<any>) {
console.log('Peeking... Found', JSON.stringify(queue.peek()));
}
function printDequeue(queue: StackifiedQueue<any>) {
console.log('Dequeued:', JSON.stringify(queue.dequeue()));
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
const ATLA = new StackifiedQueue<string>();
printPeekQueue(ATLA);
ATLA.enqueue('Sokka');
ATLA.enqueue('Katara');
printPeekQueue(ATLA);
ATLA.enqueue('Aang');
ATLA.enqueue('Appa');
printQueue(ATLA);
printDequeue(ATLA);
printDequeue(ATLA);
printDequeue(ATLA);
printQueue(ATLA);
printDequeue(ATLA);
printQueue(ATLA);
ATLA.enqueue('Zuko');
ATLA.enqueue('Iroh');
printQueue(ATLA);
// RUN: deno run Playground/Challenges/StackifiedQueue.ts
}
// --------------------------- Terminal Output: ---------------------------
// Peeking... Found null
// Peeking... Found "Sokka"
// {"first":{"length":0,"values":[null,null]},"last":{"length":4,"values":["Sokka","Katara","Aang","Appa"]},"length":4}
// Dequeued: "Sokka"
// Dequeued: "Katara"
// Dequeued: "Aang"
// {"first":{"length":1,"values":["Appa",null,null,null]},"last":{"length":0,"values":[null,null,null,null]},"length":1}
// Dequeued: "Appa"
// {"first":{"length":0,"values":[null,null,null,null]},"last":{"length":0,"values":[null,null,null,null]},"length":0}
// {"first":{"length":0,"values":[null,null,null,null]},"last":{"length":2,"values":["Zuko","Iroh",null,null]},"length":2}
================================================
FILE: Playground/ZTM Challenges/ValidatorBST.ts
================================================
import BST from '../../Data-Structures/Trees/BinarySearchTree.ts';
import Node from '../../Data-Structures/Trees/BinaryTreeNode.ts';
export default class BinarySearchTreeValidator {
private static previousVal: number | undefined = undefined;
private static _resetValidator() {
this.previousVal = undefined;
}
public static validate(tree: BST, visualize?: boolean): boolean {
const root = tree.getRoot();
if (!root) return false;
visualize = visualize || false;
const valid: boolean = this._traverseInOrder(root, visualize);
this._resetValidator();
return valid;
}
private static _traverseInOrder(node: Node, visualize: boolean): boolean {
if (node.hasLeft()) this._traverseInOrder(node.getLeft(), visualize);
const currentValue = node.getValue();
if (visualize) console.log('\tCurrent Value:', node.getValue(), '\tPrevious:', this.previousVal);
if (!this.previousVal) this.previousVal = currentValue;
else if (currentValue < this.previousVal) return false;
else this.previousVal = currentValue;
if (node.hasRight()) this._traverseInOrder(node.getRight(), visualize);
return true;
}
}
function printBSTValidation(tree: BST, treeLabel: string) {
console.log(treeLabel, '– Original:', BinarySearchTreeValidator.validate(tree, true));
}
//---------------------------------------------------------------------
// ---------- MAIN PROGRAM ----------
//---------------------------------------------------------------------
if (import.meta.main) {
const tree1 = new BST();
tree1.insert(9);
tree1.insert(4);
tree1.insert(6);
tree1.insert(20);
tree1.insert(170);
tree1.insert(15);
tree1.insert(1);
// 9
// 4 20
// 1 6 15 170
printBSTValidation(tree1, 'Tree 1');
tree1.invertTree();
// 9
// 20 4
// 170 15 6 1
printBSTValidation(tree1, 'Tree 1');
const tree2 = new BST();
tree2.insert(16);
tree2.insert(8);
tree2.insert(32);
printBSTValidation(tree2, 'Tree 2');
tree2.invertTree();
printBSTValidation(tree2, 'Tree 2');
const tree3 = new BST();
tree3.insert(48);
tree3.insert(29);
tree3.insert(77);
tree3.insert(18);
tree3.insert(16);
tree3.insert(68);
tree3.insert(72);
tree3.insert(83);
printBSTValidation(tree3, 'Tree 3');
tree3.invertTree();
printBSTValidation(tree3, 'Tree 3');
// RUN: deno run Playground/Challenges/ValidatorBST.ts
}
// --------------------------- Terminal Output: ---------------------------
// Current Value: 1 Previous: undefined
// Current Value: 4 Previous: 1
// Current Value: 6 Previous: 4
// Current Value: 9 Previous: 6
// Current Value: 15 Previous: 9
// Current Value: 20 Previous: 15
// Current Value: 170 Previous: 20
// Tree 1 – Original: true
// Current Value: 170 Previous: undefined
// Current Value: 20 Previous: 170
// Current Value: 9 Previous: 170
// Tree 1 – Original: false
// Current Value: 8 Previous: undefined
// Current Value: 16 Previous: 8
// Current Value: 32 Previous: 16
// Tree 2 – Original: true
// Current Value: 32 Previous: undefined
// Current Value: 16 Previous: 32
// Tree 2 – Original: false
// Current Value: 16 Previous: undefined
// Current Value: 18 Previous: 16
// Current Value: 29 Previous: 18
// Current Value: 48 Previous: 29
// Current Value: 68 Previous: 48
// Current Value: 72 Previous: 68
// Current Value: 77 Previous: 72
// Current Value: 83 Previous: 77
// Tree 3 – Original: true
// Current Value: 83 Previous: undefined
// Current Value: 77 Previous: 83
// Current Value: 48 Previous: 83
// Tree 3 – Original: false
================================================
FILE: README.md
================================================
# Data Structures & Algorithms in TypeScript
## Environment
- <span title="July 2021">Deno 1.12.0</span>
- V8 9.2.230.14
- TypeScript 4.3.2
## Topics Overview
### Algorithmic Complexity Analysis
- [X] Big O Notation
- [X] Time Complexity
- [X] Space Complexity
### Data Structures
- [X] Trees
- [X] Graphs
- [X] Hash Tables
- [X] Linked Lists
- [X] Arrays/Stacks/Queues
### Algorithms
- [X] Comparison Sorting
- [X] *Merge Sort*
- [X] *Quicksort*
- [X] Searching
- [X] Linear & Binary Search
- [X] BFS & DFS
- [X] Recursion
- [X] Dynamic Programming
## Resources
- [Roadmap: Core Data Structures & Algorithms](https://coggle.it/diagram/W5E5tqYlrXvFJPsq/t/master-the-interview-click-here-for-course-link "Course and Mindmap by Andrei Neagoie")
- [The Big-O Algorithm Complexity Cheat Sheet](https://www.bigocheatsheet.com/ "Big O Cheat Sheet")
- [Algorithms & DS – Real Use Cases: PragmaticEngineer](https://blog.pragmaticengineer.com/data-structures-and-algorithms-i-actually-used-day-to-day/)
================================================
FILE: deps.ts
================================================
// ----------------------- Standard Library -----------------------
// ---------------------- Third-Party Modules ----------------------
================================================
FILE: test_deps.ts
================================================
// ----------------------- Testing Library -----------------------
export {
assertEquals,
assertNotEquals,
} from "https://deno.land/std@0.101.0/testing/asserts.ts";
// ------------------------ Miscellaneous ------------------------
import * as all_deps from "./deps.ts";
gitextract_i53d2ydn/ ├── .gitignore ├── Algorithms/ │ ├── DynamicProgramming/ │ │ ├── Basics.ts │ │ ├── Fibonacci.ts │ │ └── Knapsack.ts │ ├── README.md │ ├── Recursion/ │ │ ├── Basics.ts │ │ ├── Factorial.ts │ │ └── Fibonacci.ts │ ├── Searching/ │ │ ├── Basics.ts │ │ ├── BreadthFirstTraversal.ts │ │ ├── DepthFirstTraversals.ts │ │ └── Exercise_BFSDFSUseCases.md │ └── Sorting/ │ ├── Basics.ts │ ├── BubbleSort.ts │ ├── Data/ │ │ └── PlantFamilies.ts │ ├── Exercise_SortingUseCases.md │ ├── InsertionSort.ts │ ├── MergeSort.ts │ ├── QuickSort.ts │ └── SelectionSort.ts ├── Big-O/ │ ├── Ex1.ts │ ├── Ex2.ts │ ├── Hello_Big_O.ts │ ├── README.md │ ├── Rule3.ts │ └── n_squared.ts ├── Data-Structures/ │ ├── Arrays/ │ │ ├── Basics.ts │ │ └── MyArray.ts │ ├── Graphs/ │ │ └── SimpleGraph.ts │ ├── Hash-Tables/ │ │ └── HashTable.ts │ ├── Linked-Lists/ │ │ ├── DoublyLinkedList.ts │ │ ├── DoublyNode.ts │ │ ├── LinkedList.ts │ │ └── SinglyNode.ts │ ├── README.md │ ├── Sequential/ │ │ ├── Queue.ts │ │ ├── Stack.ts │ │ └── StackLL.ts │ └── Trees/ │ ├── BinarySearchTree.test.ts │ ├── BinarySearchTree.ts │ └── BinaryTreeNode.ts ├── Playground/ │ ├── Demos/ │ │ ├── Classes_101.ts │ │ └── Objects_101.ts │ ├── Interviews/ │ │ └── HealthcareHM.ts │ ├── Puzzles/ │ │ ├── AngryFrogs.test.ts │ │ └── AngryFrogs.ts │ └── ZTM Challenges/ │ ├── Arrays/ │ │ ├── Compare_Arrays.test.ts │ │ ├── Compare_Arrays.ts │ │ ├── Merge_Sorted_Arrays.ts │ │ ├── Reverse_String.ts │ │ └── Sum_Pair.ts │ ├── Hash-Tables/ │ │ ├── Recurring_Symbol.test.ts │ │ └── Recurring_Symbol.ts │ ├── Josephus.ts │ ├── Recursion/ │ │ └── ReverseString.ts │ ├── StackifiedQueue.ts │ └── ValidatorBST.ts ├── README.md ├── deps.ts └── test_deps.ts
SYMBOL INDEX (246 symbols across 45 files)
FILE: Algorithms/DynamicProgramming/Basics.ts
class MemoizationExample (line 2) | class MemoizationExample {
method resetCache (line 5) | public static resetCache() {
method memoizedAddTo42 (line 10) | public static memoizedAddTo42(n: number, visualize?: boolean): number {
method addTo42 (line 21) | public static addTo42(n: number): number {
function memoizedAddTo64 (line 28) | function memoizedAddTo64() {
FILE: Algorithms/DynamicProgramming/Fibonacci.ts
class FibonacciMemoized (line 4) | class FibonacciMemoized {
method nthTerm (line 12) | public static nthTerm(nth: number): number {
function fibonacciBottomUp (line 22) | function fibonacciBottomUp() {
function executionTime (line 36) | function executionTime(n: number): string {
FILE: Algorithms/Recursion/Basics.ts
function inception (line 1) | function inception(repeat: number): string {
FILE: Algorithms/Recursion/Factorial.ts
function calcFactorialRecursive (line 1) | function calcFactorialRecursive(input: number): number {
function calcFactorialIterative (line 7) | function calcFactorialIterative(input: number): number | undefined {
function validateFactorialInput (line 19) | function validateFactorialInput(input: number): boolean {
function printIterativeFactorial (line 23) | function printIterativeFactorial(input: number) {
function printRecursiveFactorial (line 31) | function printRecursiveFactorial(input: number) {
FILE: Algorithms/Recursion/Fibonacci.ts
function fibonacciRecursive (line 5) | function fibonacciRecursive(nthElement: number): number | any {
function fibonacciIterative (line 17) | function fibonacciIterative(nthElement: number): number | undefined {
function validateFibonacciInput (line 38) | function validateFibonacciInput(nthElement: number) {
function printFibonacciIterative (line 42) | function printFibonacciIterative(nthElement: number) {
function printFibonacciRecursive (line 46) | function printFibonacciRecursive(nthElement: number) {
FILE: Algorithms/Searching/BreadthFirstTraversal.ts
function recursiveBFT (line 5) | function recursiveBFT(nodeQueue: Queue<Node>, nodesTraversed: Array<numb...
function breadthFirstTraversal (line 16) | function breadthFirstTraversal(tree: BST) {
FILE: Algorithms/Searching/DepthFirstTraversals.ts
function inorderDFT (line 5) | function inorderDFT(tree: BST) {
function preorderDFT (line 26) | function preorderDFT(tree: BST) {
function postorderDFT (line 47) | function postorderDFT(tree: BST) {
FILE: Algorithms/Sorting/BubbleSort.ts
function bubbleSort (line 1) | function bubbleSort(numbersArr: Array<number>) {
function bubbleSortStrings (line 15) | function bubbleSortStrings(stringArr: Array<string>) {
FILE: Algorithms/Sorting/InsertionSort.ts
function insertionSort (line 3) | function insertionSort(inputArr: number[] | string[]) {
function executionTime (line 51) | function executionTime(method: any): string {
FILE: Algorithms/Sorting/MergeSort.ts
function merge (line 1) | function merge(left: any[], right: any[]): Array<any> {
function mergeSort (line 25) | function mergeSort(inputArr: string[] | number[]): Array<any> {
FILE: Algorithms/Sorting/QuickSort.ts
function swap (line 7) | function swap(array: Array<any>, pos1: number, pos2: number) {
function partition (line 14) | function partition(array: Array<any>, pivotIndex: number, leftBound: num...
function quickSort (line 35) | function quickSort(array: number[] | string[], leftBound: number, rightB...
FILE: Algorithms/Sorting/SelectionSort.ts
function swap (line 1) | function swap(pos1: number, pos2: number, inputArr: Array<any>): void {
function selectionSort (line 7) | function selectionSort(inputArr: Array<number> | Array<string>): Array<a...
FILE: Big-O/Ex1.ts
function anotherFunction (line 3) | function anotherFunction() {
function funChallenge (line 7) | function funChallenge(input: Array<any>): number {
FILE: Big-O/Ex2.ts
function anotherFunChallenge (line 3) | function anotherFunChallenge(input: number): void {
FILE: Big-O/Hello_Big_O.ts
function findNemo (line 6) | function findNemo(fishes: Array<string>): string {
function getFirstFish (line 24) | function getFirstFish(fishes: Array<string>) {
FILE: Big-O/Rule3.ts
function compressBoxes (line 3) | function compressBoxes(fullBoxes: Array<string>, emptyBoxes: Array<strin...
FILE: Big-O/n_squared.ts
function logAllPairs (line 5) | function logAllPairs(array: Array<any>): void {
function printNumbersThenPairSums (line 13) | function printNumbersThenPairSums(numbers: Array<number>): void {
FILE: Data-Structures/Arrays/MyArray.ts
type NumIndexedObject (line 1) | type NumIndexedObject = { [index: number]: any };
class MyArray (line 3) | class MyArray<T> {
method constructor (line 8) | constructor() {
method get (line 18) | public get(index: number): T | null {
method push (line 31) | public push(item: T): number {
method pop (line 42) | public pop(): T | null {
method deleteIndex (line 59) | public deleteIndex(index: number): T | null {
method insertItemAtIndex (line 77) | public insertItemAtIndex(index: number, item: T): number | null {
method _shiftItemsLeftAfterIndex (line 87) | private _shiftItemsLeftAfterIndex(index: number): void {
method _shiftItemsRightAtIndex (line 96) | private _shiftItemsRightAtIndex(index: number): void {
FILE: Data-Structures/Graphs/SimpleGraph.ts
type StrIndexedObject (line 1) | type StrIndexedObject = { [index: string]: Set<string> };
class SimpleGraph (line 4) | class SimpleGraph {
method constructor (line 8) | constructor() {
method getNodeCount (line 13) | public getNodeCount(): number {
method addVertex (line 17) | public addVertex(node: string) {
method addEdge (line 22) | public addEdge(node1: string, node2: string) {
method toString (line 28) | public toString(): string {
function printGraph (line 48) | function printGraph(graph: SimpleGraph) {
FILE: Data-Structures/Hash-Tables/HashTable.ts
class HashTable (line 1) | class HashTable {
method constructor (line 5) | constructor(numBuckets: number) {
method insert (line 10) | public insert(key: string, value: any): void {
method get (line 20) | public get(key: string): any {
method keys (line 33) | public keys(): string[] {
method values (line 51) | public values(): string[] {
method getSize (line 65) | public getSize(): number {
method _hash (line 69) | private _hash(key: string) {
method testHashFunction (line 80) | public testHashFunction() {
FILE: Data-Structures/Linked-Lists/DoublyLinkedList.ts
class DoublyLinkedList (line 3) | class DoublyLinkedList<T> {
method constructor (line 8) | constructor() {
method getLength (line 14) | public getLength(): number {
method isEmpty (line 18) | public isEmpty(): boolean {
method append (line 22) | public append(value: T, demo?: boolean): boolean {
method prepend (line 44) | public prepend(value: T, demo?: boolean): boolean {
method insert (line 65) | public insert(value: T, atIndex: number, demo?: boolean): boolean | nu...
method getValueAtIndex (line 98) | public getValueAtIndex(index: number): T | null {
method searchFor (line 113) | public searchFor(value: T): number | null {
method empty (line 128) | public empty(nestedCall?: boolean): boolean {
method removeElementAtIndex (line 135) | public removeElementAtIndex(index: number, demo?: boolean): T | null {
method _traverseToNode (line 173) | private _traverseToNode(index: number): Node<T> | null {
method toString (line 195) | public toString(nodesPerGroup?: number): string {
function printLinkedList (line 220) | function printLinkedList(linkedList: DoublyLinkedList<any>): void {
function printSearchFor (line 228) | function printSearchFor(value: any, linkedList: DoublyLinkedList<any>): ...
function printGetValueAtIndex (line 232) | function printGetValueAtIndex(index: number, linkedList: DoublyLinkedLis...
FILE: Data-Structures/Linked-Lists/DoublyNode.ts
class DoublyLLNode (line 1) | class DoublyLLNode<T> {
method constructor (line 6) | constructor(value: T) {
method setValue (line 12) | public setValue(value: T) {
method setNext (line 16) | public setNext(node: DoublyLLNode<T> | null) {
method setPrevious (line 20) | public setPrevious(node: DoublyLLNode<T> | null) {
method getValue (line 24) | public getValue(): T {
method getNext (line 28) | public getNext(): DoublyLLNode<T> | any {
method getPrevious (line 32) | public getPrevious(): DoublyLLNode<T> | any {
method hasNext (line 36) | public hasNext(): boolean {
method hasPrevious (line 40) | public hasPrevious(): boolean {
method toString (line 44) | public toString(): string {
FILE: Data-Structures/Linked-Lists/LinkedList.ts
class LinkedList (line 3) | class LinkedList<T> {
method constructor (line 8) | constructor() {
method getLength (line 14) | public getLength(): number {
method getHeadValue (line 18) | public getHeadValue(): T | any {
method getTailValue (line 22) | public getTailValue(): T | any {
method isEmpty (line 26) | public isEmpty(): boolean {
method empty (line 33) | public empty(): boolean {
method append (line 40) | public append(value: T): boolean {
method prepend (line 56) | public prepend(value: T): boolean {
method insert (line 71) | public insert(value: T, atIndex: number): boolean | null {
method removeElementAtIndex (line 93) | public removeElementAtIndex(index: number): T | null {
method getValueAtIndex (line 113) | public getValueAtIndex(index: number): T | null {
method searchFor (line 128) | public searchFor(value: T): number | null {
method _traverseToNode (line 140) | private _traverseToNode(index: number): Node<T> | null {
method reverse (line 152) | public reverse(): boolean {
method toArray (line 177) | public toArray(): Array<T> | any {
method toString (line 191) | public toString(nodesPerGroup?: number): string {
function printLinkedList (line 216) | function printLinkedList(linkedList: LinkedList<any>): void {
function printSearchFor (line 224) | function printSearchFor(value: any, linkedList: LinkedList<any>): void {
function printGetValueAtIndex (line 228) | function printGetValueAtIndex(index: number, linkedList: LinkedList<any>) {
function printRemoveIndex (line 232) | function printRemoveIndex(index: number, linkedList: LinkedList<any>) {
FILE: Data-Structures/Linked-Lists/SinglyNode.ts
class LinkedListNode (line 1) | class LinkedListNode<T> {
method constructor (line 5) | constructor(value: T) {
method setValue (line 10) | public setValue(value: T) {
method setNext (line 14) | public setNext(nextNode: LinkedListNode<T> | null) {
method getValue (line 18) | public getValue(): T {
method getNext (line 22) | public getNext(): LinkedListNode<T> | any {
method hasNext (line 26) | public hasNext(): boolean {
method toString (line 30) | public toString(): string {
FILE: Data-Structures/Sequential/Queue.ts
class Queue (line 4) | class Queue<T> {
method constructor (line 9) | constructor() {
method getLength (line 15) | public getLength(): number {
method isEmpty (line 19) | public isEmpty(): boolean {
method peek (line 23) | public peek(): T | null {
method enqueue (line 27) | public enqueue(value: T): boolean {
method dequeue (line 43) | public dequeue(): T | any {
function printQueue (line 58) | function printQueue(queue: Queue<any>) {
function printPeekQueue (line 62) | function printPeekQueue(queue: Queue<any>) {
function printDequeue (line 66) | function printDequeue(queue: Queue<any>) {
FILE: Data-Structures/Sequential/Stack.ts
class Stack (line 1) | class Stack<T> {
method constructor (line 5) | constructor() {
method getLength (line 10) | public getLength(): number {
method isEmpty (line 14) | public isEmpty(): boolean {
method peek (line 18) | public peek(): T | null {
method push (line 22) | public push(value: T): boolean {
method pop (line 28) | public pop() {
function printStack (line 36) | function printStack(stack: Stack<any>) {
function printPopStack (line 40) | function printPopStack(stack: Stack<any>) {
function printPeekStack (line 44) | function printPeekStack(stack: Stack<any>) {
FILE: Data-Structures/Sequential/StackLL.ts
class StackLL (line 4) | class StackLL<T> {
method constructor (line 9) | constructor() {
method getLength (line 15) | public getLength(): number {
method isEmpty (line 19) | public isEmpty(): boolean {
method peek (line 23) | public peek(): T | null {
method push (line 27) | public push(value: T): boolean {
method pop (line 51) | public pop(): T | null {
function printStack (line 69) | function printStack(stack: StackLL<any>) {
function printPopStack (line 73) | function printPopStack(stack: StackLL<any>) {
function printPeekStack (line 77) | function printPeekStack(stack: StackLL<any>) {
FILE: Data-Structures/Trees/BinarySearchTree.test.ts
method fn (line 14) | fn() {
method fn (line 31) | fn() {
FILE: Data-Structures/Trees/BinarySearchTree.ts
class BinarySearchTree (line 5) | class BinarySearchTree {
method traverse (line 7) | public static traverse(node: BNode | null) {
method constructor (line 21) | constructor() {
method getRoot (line 25) | public getRoot(): BNode | null {
method insert (line 29) | public insert(value: number) {
method lookup (line 64) | public lookup(value: number): BNode | null {
method remove (line 97) | public remove(value: number): boolean {
method invertTree (line 189) | public invertTree(): boolean {
method _invertNode (line 195) | private _invertNode(current: BNode | null) {
method _swapChildren (line 203) | private _swapChildren(node: BNode) {
method breadthFirstTraversal (line 209) | public breadthFirstTraversal() {
method equalsQuantum (line 227) | public equalsQuantum(tree: BinarySearchTree): boolean {
function printNode (line 232) | function printNode(tree: BinarySearchTree, value: number): void {
FILE: Data-Structures/Trees/BinaryTreeNode.ts
class BinaryTreeNode (line 1) | class BinaryTreeNode {
method constructor (line 6) | constructor(value: number) {
method setValue (line 12) | public setValue(value: number) {
method setLeft (line 16) | public setLeft(binaryTreeNode: BinaryTreeNode) {
method setRight (line 20) | public setRight(binaryTreeNode: BinaryTreeNode) {
method getValue (line 24) | public getValue(): number {
method getLeft (line 28) | public getLeft(): BinaryTreeNode | any {
method getRight (line 32) | public getRight(): BinaryTreeNode | any {
method hasLeft (line 36) | public hasLeft(): boolean {
method hasRight (line 41) | public hasRight(): boolean {
FILE: Playground/Demos/Classes_101.ts
class Bender (line 3) | class Bender {
method constructor (line 8) | constructor(name: string, isFemale: boolean, element: string) {
method introduce (line 16) | public introduce() {
class EarthBender (line 21) | class EarthBender extends Bender {
method constructor (line 24) | constructor(name: string, isFemale: boolean, specialty?: string) {
method earthbend (line 31) | public earthbend() {
FILE: Playground/Interviews/HealthcareHM.ts
function findNumOccurrences (line 1) | function findNumOccurrences(color: string, colorsArr: string[]): number {
function unique (line 13) | function unique(array: Array<number> | Array<string>): boolean {
FILE: Playground/Puzzles/AngryFrogs.test.ts
method fn (line 14) | fn() {
method fn (line 24) | fn() {
FILE: Playground/Puzzles/AngryFrogs.ts
function maxDistance (line 1) | function maxDistance(lilypadHeights: number[]) {
class Solution (line 6) | class Solution {
method initializeLilypadForest (line 10) | static initializeLilypadForest(lilypadHeights: number[]) {
method findMaxDistance (line 14) | static findMaxDistance(): number {
method _travelRightFrom (line 38) | private static _travelRightFrom(index: number): number {
method _travelLeftFrom (line 48) | private static _travelLeftFrom(index: number): number {
FILE: Playground/ZTM Challenges/Arrays/Compare_Arrays.test.ts
method fn (line 17) | fn() {
method fn (line 24) | fn() {
method fn (line 31) | fn() {
FILE: Playground/ZTM Challenges/Arrays/Compare_Arrays.ts
function containsCommonItemBF (line 17) | function containsCommonItemBF(arr1: Array<string>, arr2: Array<string>):...
function containsCommonItem (line 29) | function containsCommonItem(arr1: Array<string>, arr2: Array<string>): b...
function containsCommonItemSyntacticSugar (line 50) | function containsCommonItemSyntacticSugar(arr1: Array<string>, arr2: Arr...
FILE: Playground/ZTM Challenges/Arrays/Merge_Sorted_Arrays.ts
function mergeSortedArrays (line 9) | function mergeSortedArrays(arr1: number[], arr2: number[]): Array<number...
FILE: Playground/ZTM Challenges/Arrays/Reverse_String.ts
function reverseString (line 8) | function reverseString(input: string): string {
function reverseWithJavascriptVoodoo (line 20) | function reverseWithJavascriptVoodoo(input: string): string {
FILE: Playground/ZTM Challenges/Arrays/Sum_Pair.ts
function hasPairWithSumBF (line 6) | function hasPairWithSumBF(arr: number[], sum: number): boolean {
function hasPairWithSum (line 20) | function hasPairWithSum(arr: number[], sum: number) {
FILE: Playground/ZTM Challenges/Hash-Tables/Recurring_Symbol.test.ts
method fn (line 22) | fn() {
method fn (line 30) | fn() {
method fn (line 38) | fn() {
method fn (line 46) | fn() {
method fn (line 54) | fn() {
FILE: Playground/ZTM Challenges/Hash-Tables/Recurring_Symbol.ts
function firstRecurringNumber (line 23) | function firstRecurringNumber(numArray: number[]): number | undefined {
function findFirstRecurring (line 41) | function findFirstRecurring(arr: number[] | string[]): number | string |...
FILE: Playground/ZTM Challenges/Josephus.ts
class Josephus (line 1) | class Josephus {
method constructor (line 6) | constructor(numSoldiers: number) {
method setNumSoldiers (line 12) | public setNumSoldiers(numSoldiers: number) {
method getNumSoldiers (line 17) | public getNumSoldiers(): number {
method reset (line 21) | public reset(): void {
method solveBF (line 26) | public solveBF(): number {
method solveVisual (line 44) | public solveVisual(): number {
method _findNextLiving (line 76) | private _findNextLiving(index: number): number {
method _findThirdLiving (line 84) | private _findThirdLiving(index: number): number {
method _markDead (line 99) | private _markDead(index:number): number {
function printJosephusSolution (line 106) | function printJosephusSolution(circleOfKnights: Josephus) {
FILE: Playground/ZTM Challenges/Recursion/ReverseString.ts
function reverseStringRecursive (line 1) | function reverseStringRecursive(str: string): string {
function printReverseString (line 7) | function printReverseString(str: string) {
FILE: Playground/ZTM Challenges/StackifiedQueue.ts
class StackifiedQueue (line 5) | class StackifiedQueue<T> {
method constructor (line 10) | constructor() {
method getlength (line 16) | public getlength(): number {
method isEmpty (line 20) | public isEmpty(): boolean {
method enqueue (line 24) | public enqueue(value: T): boolean {
method dequeue (line 36) | public dequeue(): T | null {
method peek (line 45) | public peek(): T | null {
method _populateFirstOnTop (line 51) | private _populateFirstOnTop(): void {
method _populateLastOnTop (line 59) | private _populateLastOnTop(): void {
function printQueue (line 68) | function printQueue(queue: StackifiedQueue<any>) {
function printPeekQueue (line 72) | function printPeekQueue(queue: StackifiedQueue<any>) {
function printDequeue (line 76) | function printDequeue(queue: StackifiedQueue<any>) {
FILE: Playground/ZTM Challenges/ValidatorBST.ts
class BinarySearchTreeValidator (line 4) | class BinarySearchTreeValidator {
method _resetValidator (line 7) | private static _resetValidator() {
method validate (line 11) | public static validate(tree: BST, visualize?: boolean): boolean {
method _traverseInOrder (line 24) | private static _traverseInOrder(node: Node, visualize: boolean): boole...
function printBSTValidation (line 40) | function printBSTValidation(tree: BST, treeLabel: string) {
Condensed preview — 60 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (134K chars).
[
{
"path": ".gitignore",
"chars": 8,
"preview": "deno_dir"
},
{
"path": "Algorithms/DynamicProgramming/Basics.ts",
"chars": 2181,
"preview": "// ----------------------- Class Implementation -----------------------\nclass MemoizationExample {\n private static cach"
},
{
"path": "Algorithms/DynamicProgramming/Fibonacci.ts",
"chars": 2395,
"preview": "// ---------------- Fibonacci Sequence ----------------\n// 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144...\n\nclass Fibona"
},
{
"path": "Algorithms/DynamicProgramming/Knapsack.ts",
"chars": 311,
"preview": "\n\n\n\n//---------------------------------------------------------------------\n// ---------- MAIN PROGRAM "
},
{
"path": "Algorithms/README.md",
"chars": 2439,
"preview": "# Algorithms\n\n## Core\n- [X] Recursion\n- [X] Dynamic Programming\n- [X] Comparison Sorting\n - [X] *Merge Sort*\n - [X] *Q"
},
{
"path": "Algorithms/Recursion/Basics.ts",
"chars": 1056,
"preview": "function inception(repeat: number): string {\n // 1. Base Case(s)\n if (repeat === 0) return 'Done!\\n'; // Base "
},
{
"path": "Algorithms/Recursion/Factorial.ts",
"chars": 1907,
"preview": "function calcFactorialRecursive(input: number): number {\n if (input <= 1) return 1;\n\n return input * calcFactorialRecu"
},
{
"path": "Algorithms/Recursion/Fibonacci.ts",
"chars": 3442,
"preview": "// ---------------- Fibonacci Sequence ----------------\n// 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144...\n\n// Time Comp"
},
{
"path": "Algorithms/Searching/Basics.ts",
"chars": 349,
"preview": "var beasts = ['Centaur', 'Godzilla', 'Mosura', 'Minotaur', 'Hydra', 'Nessie'];\n\nbeasts.indexOf('Godzilla'); //"
},
{
"path": "Algorithms/Searching/BreadthFirstTraversal.ts",
"chars": 1596,
"preview": "import BST from '../../Data-Structures/Trees/BinarySearchTree.ts';\nimport Node from '../../Data-Structures/Trees/BinaryT"
},
{
"path": "Algorithms/Searching/DepthFirstTraversals.ts",
"chars": 3050,
"preview": "import BST from '../../Data-Structures/Trees/BinarySearchTree.ts';\nimport Node from '../../Data-Structures/Trees/BinaryT"
},
{
"path": "Algorithms/Searching/Exercise_BFSDFSUseCases.md",
"chars": 520,
"preview": "# Graph Traversal Use Cases\n\n## Which traversal algorithm would be best for each situation? (BFS or DFS)\n\n1) If you know"
},
{
"path": "Algorithms/Sorting/Basics.ts",
"chars": 245,
"preview": "const spanish = ['único', 'árbol', 'cosas', 'fútbol'];\n\nspanish.sort(function(a,b) {\n return a.localeCompare(b, 'es');\n"
},
{
"path": "Algorithms/Sorting/BubbleSort.ts",
"chars": 1625,
"preview": "function bubbleSort(numbersArr: Array<number>) {\n\n for (let i=0; i < numbersArr.length-1; ++i) {\n for (let j=0; j < "
},
{
"path": "Algorithms/Sorting/Data/PlantFamilies.ts",
"chars": 5233,
"preview": "export const plant_families = {\n short_list: [\n \"Loranthaceae\",\n \"Clusiaceae\",\n \"Aristolochiaceae\",\n \"Myrta"
},
{
"path": "Algorithms/Sorting/Exercise_SortingUseCases.md",
"chars": 769,
"preview": "# Sorting Use Cases\n\n## Which sorting algorithm would be a good candidate for each situation?\n\n1) Sort 10 schools around"
},
{
"path": "Algorithms/Sorting/InsertionSort.ts",
"chars": 3762,
"preview": "import { plant_families } from './Data/PlantFamilies.ts';\n\nfunction insertionSort(inputArr: number[] | string[]) {\n\n if"
},
{
"path": "Algorithms/Sorting/MergeSort.ts",
"chars": 1914,
"preview": "function merge(left: any[], right: any[]): Array<any> {\n const result = [];\n\n let leftIndex = 0;\n let rightIndex = 0;"
},
{
"path": "Algorithms/Sorting/QuickSort.ts",
"chars": 2408,
"preview": "/**\n * Given an array, swaps two elements at the specified positions (indices).\n * @param array Array in which to swap e"
},
{
"path": "Algorithms/Sorting/SelectionSort.ts",
"chars": 1453,
"preview": "function swap(pos1: number, pos2: number, inputArr: Array<any>): void {\n const placeholder = inputArr[pos1];\n inputArr"
},
{
"path": "Big-O/Ex1.ts",
"chars": 503,
"preview": "// Exercise 1 -----------------------------------------\n\nfunction anotherFunction() {\n // unknown runtime\n}\n\nfunction f"
},
{
"path": "Big-O/Ex2.ts",
"chars": 533,
"preview": "// Exercise 2 -----------------------------------------\n\nfunction anotherFunChallenge(input: number): void {\n let a = 5"
},
{
"path": "Big-O/Hello_Big_O.ts",
"chars": 1059,
"preview": "\nconst nemo = ['nemo'];\nconst fishColony = ['dory', 'bruce', 'marlin', 'nemo', 'gill', 'bloat', 'nigel', 'squirt', 'darl"
},
{
"path": "Big-O/README.md",
"chars": 937,
"preview": "# Algorithm Time-Complexity Analysis\n\n**Goal:** Understand how the runtime of an algorithm is affected by an increasing "
},
{
"path": "Big-O/Rule3.ts",
"chars": 328,
"preview": "// Rule 3: Different inputs should have different variables.--------------------\n\nfunction compressBoxes(fullBoxes: Arra"
},
{
"path": "Big-O/n_squared.ts",
"chars": 896,
"preview": "// Examples of Quadratic Big O Runtime — O(n^2) ------------------\n\nconst boxes = [\"a\", \"b\", \"c\", \"d\", \"e\"];\n\nfunction l"
},
{
"path": "Data-Structures/Arrays/Basics.ts",
"chars": 898,
"preview": "// RUN: deno run Data-Structures/Arrays/Basics.ts\n\n\nconst teamAvatar = ['Aang','Appa','Momo','Katara','Sokka'];\n\n// Pu"
},
{
"path": "Data-Structures/Arrays/MyArray.ts",
"chars": 4070,
"preview": "type NumIndexedObject = { [index: number]: any };\n\nexport default class MyArray<T> {\n\n public length: number;\n private"
},
{
"path": "Data-Structures/Graphs/SimpleGraph.ts",
"chars": 2263,
"preview": "type StrIndexedObject = { [index: string]: Set<string> };\n\n\nexport default class SimpleGraph {\n private numberOfNodes: "
},
{
"path": "Data-Structures/Hash-Tables/HashTable.ts",
"chars": 2455,
"preview": "export class HashTable {\n private size: number;\n private data: Array<Array<any>>;\n\n constructor(numBuckets: number) {"
},
{
"path": "Data-Structures/Linked-Lists/DoublyLinkedList.ts",
"chars": 11410,
"preview": "import Node from './DoublyNode.ts';\n\nexport default class DoublyLinkedList<T> {\n private head: Node<T> | null;\n privat"
},
{
"path": "Data-Structures/Linked-Lists/DoublyNode.ts",
"chars": 937,
"preview": "export default class DoublyLLNode<T> {\n private value: T;\n private next: DoublyLLNode<T> | null;\n private previous: D"
},
{
"path": "Data-Structures/Linked-Lists/LinkedList.ts",
"chars": 10346,
"preview": "import Node from './SinglyNode.ts';\n\nexport default class LinkedList<T> {\n private head: Node<T> | null;\n private tail"
},
{
"path": "Data-Structures/Linked-Lists/SinglyNode.ts",
"chars": 623,
"preview": "export default class LinkedListNode<T> {\n private value: T;\n private next: LinkedListNode<T> | null;\n\n constructor(va"
},
{
"path": "Data-Structures/README.md",
"chars": 1726,
"preview": "# Data Structures\n\n## Core\n- [X] Arrays\n- [X] Hash Tables\n- [X] Stacks\n- [X] Queues\n- [X] Linked Lists\n- [X] Trees\n - ["
},
{
"path": "Data-Structures/Sequential/Queue.ts",
"chars": 2954,
"preview": "import Node from '../Linked-Lists/SinglyNode.ts';\n\n\nexport default class Queue<T> {\n private last: Node<T> | null;\n pr"
},
{
"path": "Data-Structures/Sequential/Stack.ts",
"chars": 1997,
"preview": "export default class Stack<T> {\n private length: number;\n private values: Array<T>;\n\n constructor() {\n this.length"
},
{
"path": "Data-Structures/Sequential/StackLL.ts",
"chars": 3392,
"preview": "import Node from '../Linked-Lists/SinglyNode.ts';\n\n\nexport default class StackLL<T> {\n private top: Node<T> | null;\n p"
},
{
"path": "Data-Structures/Trees/BinarySearchTree.test.ts",
"chars": 1060,
"preview": "import { assertEquals, assertNotEquals } from '../../test_deps.ts';\n\nimport BinarySearchTree from './BinarySearchTree.ts"
},
{
"path": "Data-Structures/Trees/BinarySearchTree.ts",
"chars": 9231,
"preview": "import BNode from './BinaryTreeNode.ts';\nimport Queue from '../Sequential/Queue.ts';\n\n\nexport default class BinarySearch"
},
{
"path": "Data-Structures/Trees/BinaryTreeNode.ts",
"chars": 866,
"preview": "export default class BinaryTreeNode {\n private value: number;\n private left: BinaryTreeNode | null;\n private right: B"
},
{
"path": "Playground/Demos/Classes_101.ts",
"chars": 999,
"preview": "// RUN: deno run Playground/Demos/Classes_101.ts\n\nclass Bender {\n protected name: string;\n protected isFemale: boolean"
},
{
"path": "Playground/Demos/Objects_101.ts",
"chars": 1676,
"preview": "// RUN: deno run Playground/Demos/Objects_101.ts\n\nconsole.log('------------------------- Episode 1 ---------------------"
},
{
"path": "Playground/Interviews/HealthcareHM.ts",
"chars": 629,
"preview": "function findNumOccurrences(color: string, colorsArr: string[]): number {\n let occurrences = 0;\n\n for (let c of colors"
},
{
"path": "Playground/Puzzles/AngryFrogs.test.ts",
"chars": 707,
"preview": "import { assertEquals } from '../../test_deps.ts';\n\nimport maxDistance from './AngryFrogs.ts';\n\n\n// RUN: deno test Playg"
},
{
"path": "Playground/Puzzles/AngryFrogs.ts",
"chars": 2135,
"preview": "export default function maxDistance(lilypadHeights: number[]) {\n Solution.initializeLilypadForest(lilypadHeights);\n "
},
{
"path": "Playground/ZTM Challenges/Arrays/Compare_Arrays.test.ts",
"chars": 915,
"preview": "import { assertEquals, assertNotEquals } from \"../../../test_deps.ts\";\n\nimport { containsCommonItem } from \"./Compare_Ar"
},
{
"path": "Playground/ZTM Challenges/Arrays/Compare_Arrays.ts",
"chars": 1864,
"preview": "// Given 2 arrays, create a function that let's a user \n// know (true/false) whether these two arrays contain any common"
},
{
"path": "Playground/ZTM Challenges/Arrays/Merge_Sorted_Arrays.ts",
"chars": 1119,
"preview": "// Challenge: Given two sorted numerical arrays,\n// merge them into a sorted array\n//\n// Example:\n// Input: [1,3,"
},
{
"path": "Playground/ZTM Challenges/Arrays/Reverse_String.ts",
"chars": 745,
"preview": "// Challenge: Reverse the characters of a string, preserving\n// capitalization and spaces\n//\n// Example:\n// Input "
},
{
"path": "Playground/ZTM Challenges/Arrays/Sum_Pair.ts",
"chars": 859,
"preview": "// Challenge: Given an array of unordered numbers and a sum,\n// is there a pair of numbers which add up to the sum?\n\n\n"
},
{
"path": "Playground/ZTM Challenges/Hash-Tables/Recurring_Symbol.test.ts",
"chars": 1376,
"preview": "import { assertEquals } from \"../../../test_deps.ts\";\n\nimport {\n firstRecurringNumber,\n findFirstRecurring,\n} from \"./"
},
{
"path": "Playground/ZTM Challenges/Hash-Tables/Recurring_Symbol.ts",
"chars": 1353,
"preview": "// ---------- Google Interview Question ----------\n// Given an array = [2,5,1,2,3,5,1,2,4]:\n// It should return 2\n\n// "
},
{
"path": "Playground/ZTM Challenges/Josephus.ts",
"chars": 4948,
"preview": "export default class Josephus {\n private numberOfSoldiers: number;\n private circleOfSoldiers: Array<boolean>;\n privat"
},
{
"path": "Playground/ZTM Challenges/Recursion/ReverseString.ts",
"chars": 698,
"preview": "function reverseStringRecursive(str: string): string {\n if (str.length===0) return \"\";\n\n return reverseStringRecursive"
},
{
"path": "Playground/ZTM Challenges/StackifiedQueue.ts",
"chars": 3223,
"preview": "import Stack from '../../Data-Structures/Sequential/Stack.ts';\n\n// Ahhhhh! What a glorious day to do things just because"
},
{
"path": "Playground/ZTM Challenges/ValidatorBST.ts",
"chars": 3888,
"preview": "import BST from '../../Data-Structures/Trees/BinarySearchTree.ts';\nimport Node from '../../Data-Structures/Trees/BinaryT"
},
{
"path": "README.md",
"chars": 1012,
"preview": "# Data Structures & Algorithms in TypeScript\n\n## Environment\n- <span title=\"July 2021\">Deno 1.12.0</span>\n- V8 9.2.230.1"
},
{
"path": "deps.ts",
"chars": 138,
"preview": "// ----------------------- Standard Library -----------------------\n\n\n// ---------------------- Third-Party Modules ----"
},
{
"path": "test_deps.ts",
"chars": 276,
"preview": "// ----------------------- Testing Library -----------------------\nexport {\n assertEquals,\n assertNotEquals,\n} from \"h"
}
]
About this extraction
This page contains the full source code of the CoffeelessProgrammer/Data-Structures-and-Algorithms-TS GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 60 files (120.8 KB), approximately 34.7k tokens, and a symbol index with 246 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.