From 1b6e15095ee35de04f7ffb87d0e958fbfbec622f Mon Sep 17 00:00:00 2001 From: souzaravinho Date: Sat, 30 Aug 2025 21:21:54 -0300 Subject: [PATCH] Revert "Ad hoc versions of MinHeap, MaxHeap, and DisjointSet (#1117)" This reverts commit 2c67b48c21eed86aafbb4d09065ffe391b4fc7e4. --- .../disjoint-set/DisjointSetAdhoc.js | 78 ------------ src/data-structures/disjoint-set/README.md | 5 - .../__test__/DisjointSetAdhoc.test.js | 50 -------- src/data-structures/heap/MaxHeapAdhoc.js | 115 ----------------- src/data-structures/heap/MinHeapAdhoc.js | 117 ------------------ src/data-structures/heap/README.md | 5 - .../heap/__test__/MaxHeapAdhoc.test.js | 91 -------------- .../heap/__test__/MinHeapAdhoc.test.js | 91 -------------- 8 files changed, 552 deletions(-) delete mode 100644 src/data-structures/disjoint-set/DisjointSetAdhoc.js delete mode 100644 src/data-structures/disjoint-set/__test__/DisjointSetAdhoc.test.js delete mode 100644 src/data-structures/heap/MaxHeapAdhoc.js delete mode 100644 src/data-structures/heap/MinHeapAdhoc.js delete mode 100644 src/data-structures/heap/__test__/MaxHeapAdhoc.test.js delete mode 100644 src/data-structures/heap/__test__/MinHeapAdhoc.test.js diff --git a/src/data-structures/disjoint-set/DisjointSetAdhoc.js b/src/data-structures/disjoint-set/DisjointSetAdhoc.js deleted file mode 100644 index 9653418042..0000000000 --- a/src/data-structures/disjoint-set/DisjointSetAdhoc.js +++ /dev/null @@ -1,78 +0,0 @@ -/** - * The minimalistic (ad hoc) version of a DisjointSet (or a UnionFind) data structure - * that doesn't have external dependencies and that is easy to copy-paste and - * use during the coding interview if allowed by the interviewer (since many - * data structures in JS are missing). - * - * Time Complexity: - * - * - Constructor: O(N) - * - Find: O(α(N)) - * - Union: O(α(N)) - * - Connected: O(α(N)) - * - * Where N is the number of vertices in the graph. - * α refers to the Inverse Ackermann function. - * In practice, we assume it's a constant. - * In other words, O(α(N)) is regarded as O(1) on average. - */ -class DisjointSetAdhoc { - /** - * Initializes the set of specified size. - * @param {number} size - */ - constructor(size) { - // The index of a cell is an id of the node in a set. - // The value of a cell is an id (index) of the root node. - // By default, the node is a parent of itself. - this.roots = new Array(size).fill(0).map((_, i) => i); - - // Using the heights array to record the height of each node. - // By default each node has a height of 1 because it has no children. - this.heights = new Array(size).fill(1); - } - - /** - * Finds the root of node `a` - * @param {number} a - * @returns {number} - */ - find(a) { - if (a === this.roots[a]) return a; - this.roots[a] = this.find(this.roots[a]); - return this.roots[a]; - } - - /** - * Joins the `a` and `b` nodes into same set. - * @param {number} a - * @param {number} b - * @returns {number} - */ - union(a, b) { - const aRoot = this.find(a); - const bRoot = this.find(b); - - if (aRoot === bRoot) return; - - if (this.heights[aRoot] > this.heights[bRoot]) { - this.roots[bRoot] = aRoot; - } else if (this.heights[aRoot] < this.heights[bRoot]) { - this.roots[aRoot] = bRoot; - } else { - this.roots[bRoot] = aRoot; - this.heights[aRoot] += 1; - } - } - - /** - * Checks if `a` and `b` belong to the same set. - * @param {number} a - * @param {number} b - */ - connected(a, b) { - return this.find(a) === this.find(b); - } -} - -export default DisjointSetAdhoc; diff --git a/src/data-structures/disjoint-set/README.md b/src/data-structures/disjoint-set/README.md index 772f68191b..44bcfa2769 100644 --- a/src/data-structures/disjoint-set/README.md +++ b/src/data-structures/disjoint-set/README.md @@ -19,11 +19,6 @@ _MakeSet_ creates 8 singletons. After some operations of _Union_, some sets are grouped together. -## Implementation - -- [DisjointSet.js](./DisjointSet.js) -- [DisjointSetAdhoc.js](./DisjointSetAdhoc.js) - The minimalistic (ad hoc) version of a DisjointSet (or a UnionFind) data structure that doesn't have external dependencies and that is easy to copy-paste and use during the coding interview if allowed by the interviewer (since many data structures in JS are missing). - ## References - [Wikipedia](https://en.wikipedia.org/wiki/Disjoint-set_data_structure) diff --git a/src/data-structures/disjoint-set/__test__/DisjointSetAdhoc.test.js b/src/data-structures/disjoint-set/__test__/DisjointSetAdhoc.test.js deleted file mode 100644 index f7be0fcde9..0000000000 --- a/src/data-structures/disjoint-set/__test__/DisjointSetAdhoc.test.js +++ /dev/null @@ -1,50 +0,0 @@ -import DisjointSetAdhoc from '../DisjointSetAdhoc'; - -describe('DisjointSetAdhoc', () => { - it('should create unions and find connected elements', () => { - const set = new DisjointSetAdhoc(10); - - // 1-2-5-6-7 3-8-9 4 - set.union(1, 2); - set.union(2, 5); - set.union(5, 6); - set.union(6, 7); - - set.union(3, 8); - set.union(8, 9); - - expect(set.connected(1, 5)).toBe(true); - expect(set.connected(5, 7)).toBe(true); - expect(set.connected(3, 8)).toBe(true); - - expect(set.connected(4, 9)).toBe(false); - expect(set.connected(4, 7)).toBe(false); - - // 1-2-5-6-7 3-8-9-4 - set.union(9, 4); - - expect(set.connected(4, 9)).toBe(true); - expect(set.connected(4, 3)).toBe(true); - expect(set.connected(8, 4)).toBe(true); - - expect(set.connected(8, 7)).toBe(false); - expect(set.connected(2, 3)).toBe(false); - }); - - it('should keep the height of the tree small', () => { - const set = new DisjointSetAdhoc(10); - - // 1-2-6-7-9 1 3 4 5 - set.union(7, 6); - set.union(1, 2); - set.union(2, 6); - set.union(1, 7); - set.union(9, 1); - - expect(set.connected(1, 7)).toBe(true); - expect(set.connected(6, 9)).toBe(true); - expect(set.connected(4, 9)).toBe(false); - - expect(Math.max(...set.heights)).toBe(3); - }); -}); diff --git a/src/data-structures/heap/MaxHeapAdhoc.js b/src/data-structures/heap/MaxHeapAdhoc.js deleted file mode 100644 index b9d69c59e0..0000000000 --- a/src/data-structures/heap/MaxHeapAdhoc.js +++ /dev/null @@ -1,115 +0,0 @@ -/** - * The minimalistic (ad hoc) version of a MaxHeap data structure that doesn't have - * external dependencies and that is easy to copy-paste and use during the - * coding interview if allowed by the interviewer (since many data - * structures in JS are missing). - */ -class MaxHeapAdhoc { - constructor(heap = []) { - this.heap = []; - heap.forEach(this.add); - } - - add(num) { - this.heap.push(num); - this.heapifyUp(); - } - - peek() { - return this.heap[0]; - } - - poll() { - if (this.heap.length === 0) return undefined; - const top = this.heap[0]; - this.heap[0] = this.heap[this.heap.length - 1]; - this.heap.pop(); - this.heapifyDown(); - return top; - } - - isEmpty() { - return this.heap.length === 0; - } - - toString() { - return this.heap.join(','); - } - - heapifyUp() { - let nodeIndex = this.heap.length - 1; - while (nodeIndex > 0) { - const parentIndex = this.getParentIndex(nodeIndex); - if (this.heap[parentIndex] >= this.heap[nodeIndex]) break; - this.swap(parentIndex, nodeIndex); - nodeIndex = parentIndex; - } - } - - heapifyDown() { - let nodeIndex = 0; - - while ( - ( - this.hasLeftChild(nodeIndex) && this.heap[nodeIndex] < this.leftChild(nodeIndex) - ) - || ( - this.hasRightChild(nodeIndex) && this.heap[nodeIndex] < this.rightChild(nodeIndex) - ) - ) { - const leftIndex = this.getLeftChildIndex(nodeIndex); - const rightIndex = this.getRightChildIndex(nodeIndex); - const left = this.leftChild(nodeIndex); - const right = this.rightChild(nodeIndex); - - if (this.hasLeftChild(nodeIndex) && this.hasRightChild(nodeIndex)) { - if (left >= right) { - this.swap(leftIndex, nodeIndex); - nodeIndex = leftIndex; - } else { - this.swap(rightIndex, nodeIndex); - nodeIndex = rightIndex; - } - } else if (this.hasLeftChild(nodeIndex)) { - this.swap(leftIndex, nodeIndex); - nodeIndex = leftIndex; - } - } - } - - getLeftChildIndex(parentIndex) { - return (2 * parentIndex) + 1; - } - - getRightChildIndex(parentIndex) { - return (2 * parentIndex) + 2; - } - - getParentIndex(childIndex) { - return Math.floor((childIndex - 1) / 2); - } - - hasLeftChild(parentIndex) { - return this.getLeftChildIndex(parentIndex) < this.heap.length; - } - - hasRightChild(parentIndex) { - return this.getRightChildIndex(parentIndex) < this.heap.length; - } - - leftChild(parentIndex) { - return this.heap[this.getLeftChildIndex(parentIndex)]; - } - - rightChild(parentIndex) { - return this.heap[this.getRightChildIndex(parentIndex)]; - } - - swap(indexOne, indexTwo) { - const tmp = this.heap[indexTwo]; - this.heap[indexTwo] = this.heap[indexOne]; - this.heap[indexOne] = tmp; - } -} - -export default MaxHeapAdhoc; diff --git a/src/data-structures/heap/MinHeapAdhoc.js b/src/data-structures/heap/MinHeapAdhoc.js deleted file mode 100644 index c70692f3de..0000000000 --- a/src/data-structures/heap/MinHeapAdhoc.js +++ /dev/null @@ -1,117 +0,0 @@ -/** - * The minimalistic (ad hoc) version of a MinHeap data structure that doesn't have - * external dependencies and that is easy to copy-paste and use during the - * coding interview if allowed by the interviewer (since many data - * structures in JS are missing). - */ -class MinHeapAdhoc { - constructor(heap = []) { - this.heap = []; - heap.forEach(this.add); - } - - add(num) { - this.heap.push(num); - this.heapifyUp(); - } - - peek() { - return this.heap[0]; - } - - poll() { - if (this.heap.length === 0) return undefined; - const top = this.heap[0]; - this.heap[0] = this.heap[this.heap.length - 1]; - this.heap.pop(); - this.heapifyDown(); - return top; - } - - isEmpty() { - return this.heap.length === 0; - } - - toString() { - return this.heap.join(','); - } - - heapifyUp() { - let nodeIndex = this.heap.length - 1; - while (nodeIndex > 0) { - const parentIndex = this.getParentIndex(nodeIndex); - if (this.heap[parentIndex] <= this.heap[nodeIndex]) break; - this.swap(parentIndex, nodeIndex); - nodeIndex = parentIndex; - } - } - - heapifyDown() { - let nodeIndex = 0; - - while ( - ( - this.hasLeftChild(nodeIndex) - && this.heap[nodeIndex] > this.leftChild(nodeIndex) - ) - || ( - this.hasRightChild(nodeIndex) - && this.heap[nodeIndex] > this.rightChild(nodeIndex) - ) - ) { - const leftIndex = this.getLeftChildIndex(nodeIndex); - const rightIndex = this.getRightChildIndex(nodeIndex); - const left = this.leftChild(nodeIndex); - const right = this.rightChild(nodeIndex); - - if (this.hasLeftChild(nodeIndex) && this.hasRightChild(nodeIndex)) { - if (left <= right) { - this.swap(leftIndex, nodeIndex); - nodeIndex = leftIndex; - } else { - this.swap(rightIndex, nodeIndex); - nodeIndex = rightIndex; - } - } else if (this.hasLeftChild(nodeIndex)) { - this.swap(leftIndex, nodeIndex); - nodeIndex = leftIndex; - } - } - } - - getLeftChildIndex(parentIndex) { - return 2 * parentIndex + 1; - } - - getRightChildIndex(parentIndex) { - return 2 * parentIndex + 2; - } - - getParentIndex(childIndex) { - return Math.floor((childIndex - 1) / 2); - } - - hasLeftChild(parentIndex) { - return this.getLeftChildIndex(parentIndex) < this.heap.length; - } - - hasRightChild(parentIndex) { - return this.getRightChildIndex(parentIndex) < this.heap.length; - } - - leftChild(parentIndex) { - return this.heap[this.getLeftChildIndex(parentIndex)]; - } - - rightChild(parentIndex) { - return this.heap[this.getRightChildIndex(parentIndex)]; - } - - swap(indexOne, indexTwo) { - const tmp = this.heap[indexTwo]; - this.heap[indexTwo] = this.heap[indexOne]; - this.heap[indexOne] = tmp; - } -} - -export default MinHeapAdhoc; diff --git a/src/data-structures/heap/README.md b/src/data-structures/heap/README.md index 392c5c96bc..824d646043 100644 --- a/src/data-structures/heap/README.md +++ b/src/data-structures/heap/README.md @@ -58,11 +58,6 @@ Where: > In this repository, the [MaxHeap.js](./MaxHeap.js) and [MinHeap.js](./MinHeap.js) are examples of the **Binary** heap. -## Implementation - -- [MaxHeap.js](./MaxHeap.js) and [MinHeap.js](./MinHeap.js) -- [MaxHeapAdhoc.js](./MaxHeapAdhoc.js) and [MinHeapAdhoc.js](./MinHeapAdhoc.js) - The minimalistic (ad hoc) version of a MinHeap/MaxHeap data structure that doesn't have external dependencies and that is easy to copy-paste and use during the coding interview if allowed by the interviewer (since many data structures in JS are missing). - ## References - [Wikipedia](https://en.wikipedia.org/wiki/Heap_(data_structure)) diff --git a/src/data-structures/heap/__test__/MaxHeapAdhoc.test.js b/src/data-structures/heap/__test__/MaxHeapAdhoc.test.js deleted file mode 100644 index 0217a98ddf..0000000000 --- a/src/data-structures/heap/__test__/MaxHeapAdhoc.test.js +++ /dev/null @@ -1,91 +0,0 @@ -import MaxHeap from '../MaxHeapAdhoc'; - -describe('MaxHeapAdhoc', () => { - it('should create an empty max heap', () => { - const maxHeap = new MaxHeap(); - - expect(maxHeap).toBeDefined(); - expect(maxHeap.peek()).toBe(undefined); - expect(maxHeap.isEmpty()).toBe(true); - }); - - it('should add items to the heap and heapify it up', () => { - const maxHeap = new MaxHeap(); - - maxHeap.add(5); - expect(maxHeap.isEmpty()).toBe(false); - expect(maxHeap.peek()).toBe(5); - expect(maxHeap.toString()).toBe('5'); - - maxHeap.add(3); - expect(maxHeap.peek()).toBe(5); - expect(maxHeap.toString()).toBe('5,3'); - - maxHeap.add(10); - expect(maxHeap.peek()).toBe(10); - expect(maxHeap.toString()).toBe('10,3,5'); - - maxHeap.add(1); - expect(maxHeap.peek()).toBe(10); - expect(maxHeap.toString()).toBe('10,3,5,1'); - - maxHeap.add(1); - expect(maxHeap.peek()).toBe(10); - expect(maxHeap.toString()).toBe('10,3,5,1,1'); - - expect(maxHeap.poll()).toBe(10); - expect(maxHeap.toString()).toBe('5,3,1,1'); - - expect(maxHeap.poll()).toBe(5); - expect(maxHeap.toString()).toBe('3,1,1'); - - expect(maxHeap.poll()).toBe(3); - expect(maxHeap.toString()).toBe('1,1'); - }); - - it('should poll items from the heap and heapify it down', () => { - const maxHeap = new MaxHeap(); - - maxHeap.add(5); - maxHeap.add(3); - maxHeap.add(10); - maxHeap.add(11); - maxHeap.add(1); - - expect(maxHeap.toString()).toBe('11,10,5,3,1'); - - expect(maxHeap.poll()).toBe(11); - expect(maxHeap.toString()).toBe('10,3,5,1'); - - expect(maxHeap.poll()).toBe(10); - expect(maxHeap.toString()).toBe('5,3,1'); - - expect(maxHeap.poll()).toBe(5); - expect(maxHeap.toString()).toBe('3,1'); - - expect(maxHeap.poll()).toBe(3); - expect(maxHeap.toString()).toBe('1'); - - expect(maxHeap.poll()).toBe(1); - expect(maxHeap.toString()).toBe(''); - - expect(maxHeap.poll()).toBe(undefined); - expect(maxHeap.toString()).toBe(''); - }); - - it('should heapify down through the right branch as well', () => { - const maxHeap = new MaxHeap(); - - maxHeap.add(3); - maxHeap.add(12); - maxHeap.add(10); - - expect(maxHeap.toString()).toBe('12,3,10'); - - maxHeap.add(11); - expect(maxHeap.toString()).toBe('12,11,10,3'); - - expect(maxHeap.poll()).toBe(12); - expect(maxHeap.toString()).toBe('11,3,10'); - }); -}); diff --git a/src/data-structures/heap/__test__/MinHeapAdhoc.test.js b/src/data-structures/heap/__test__/MinHeapAdhoc.test.js deleted file mode 100644 index 766b307ff0..0000000000 --- a/src/data-structures/heap/__test__/MinHeapAdhoc.test.js +++ /dev/null @@ -1,91 +0,0 @@ -import MinHeapAdhoc from '../MinHeapAdhoc'; - -describe('MinHeapAdhoc', () => { - it('should create an empty min heap', () => { - const minHeap = new MinHeapAdhoc(); - - expect(minHeap).toBeDefined(); - expect(minHeap.peek()).toBe(undefined); - expect(minHeap.isEmpty()).toBe(true); - }); - - it('should add items to the heap and heapify it up', () => { - const minHeap = new MinHeapAdhoc(); - - minHeap.add(5); - expect(minHeap.isEmpty()).toBe(false); - expect(minHeap.peek()).toBe(5); - expect(minHeap.toString()).toBe('5'); - - minHeap.add(3); - expect(minHeap.peek()).toBe(3); - expect(minHeap.toString()).toBe('3,5'); - - minHeap.add(10); - expect(minHeap.peek()).toBe(3); - expect(minHeap.toString()).toBe('3,5,10'); - - minHeap.add(1); - expect(minHeap.peek()).toBe(1); - expect(minHeap.toString()).toBe('1,3,10,5'); - - minHeap.add(1); - expect(minHeap.peek()).toBe(1); - expect(minHeap.toString()).toBe('1,1,10,5,3'); - - expect(minHeap.poll()).toBe(1); - expect(minHeap.toString()).toBe('1,3,10,5'); - - expect(minHeap.poll()).toBe(1); - expect(minHeap.toString()).toBe('3,5,10'); - - expect(minHeap.poll()).toBe(3); - expect(minHeap.toString()).toBe('5,10'); - }); - - it('should poll items from the heap and heapify it down', () => { - const minHeap = new MinHeapAdhoc(); - - minHeap.add(5); - minHeap.add(3); - minHeap.add(10); - minHeap.add(11); - minHeap.add(1); - - expect(minHeap.toString()).toBe('1,3,10,11,5'); - - expect(minHeap.poll()).toBe(1); - expect(minHeap.toString()).toBe('3,5,10,11'); - - expect(minHeap.poll()).toBe(3); - expect(minHeap.toString()).toBe('5,11,10'); - - expect(minHeap.poll()).toBe(5); - expect(minHeap.toString()).toBe('10,11'); - - expect(minHeap.poll()).toBe(10); - expect(minHeap.toString()).toBe('11'); - - expect(minHeap.poll()).toBe(11); - expect(minHeap.toString()).toBe(''); - - expect(minHeap.poll()).toBe(undefined); - expect(minHeap.toString()).toBe(''); - }); - - it('should heapify down through the right branch as well', () => { - const minHeap = new MinHeapAdhoc(); - - minHeap.add(3); - minHeap.add(12); - minHeap.add(10); - - expect(minHeap.toString()).toBe('3,12,10'); - - minHeap.add(11); - expect(minHeap.toString()).toBe('3,11,10,12'); - - expect(minHeap.poll()).toBe(3); - expect(minHeap.toString()).toBe('10,11,12'); - }); -});