From a02a9a94d20a3a02ea48dd2e1a780f4b6e9e7fe3 Mon Sep 17 00:00:00 2001 From: Revone Date: Thu, 7 Dec 2023 19:34:20 +0800 Subject: [PATCH] refactor: Rewrite the lastKey method. The BinaryTree.add method filters out duplicate additions. Rename popLast and popFirst to pollLast and pollFirst. --- CHANGELOG.md | 2 +- package.json | 2 +- .../binary-tree/binary-tree.ts | 15 ++--- src/data-structures/binary-tree/bst.ts | 64 +++++++++++-------- src/data-structures/hash/hash-map.ts | 2 +- .../linked-list/doubly-linked-list.ts | 8 +-- .../linked-list/singly-linked-list.ts | 8 +-- src/data-structures/queue/deque.ts | 20 +++--- src/data-structures/queue/queue.ts | 2 +- .../data-structures/binary-tree/rb-tree.ts | 2 +- src/types/data-structures/heap/heap.ts | 2 +- .../priority-queue/priority-queue.ts | 2 +- .../linked-list/singly-linked-list.test.ts | 4 +- test/unit/data-structures/queue/deque.test.ts | 30 ++++----- 14 files changed, 85 insertions(+), 78 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7adcd4e..89840e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ All notable changes to this project will be documented in this file. - [Semantic Versioning](https://semver.org/spec/v2.0.0.html) - [`auto-changelog`](https://github.com/CookPete/auto-changelog) -## [v1.48.5](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.48.6](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes diff --git a/package.json b/package.json index 9c3ce53..20d2bfe 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "data-structure-typed", "version": "1.48.6", - "description": "Data Structures of Javascript & TypeScript. Heap, Binary Tree, Red Black Tree, Linked List, Deque, Trie, HashMap, Directed Graph, Undirected Graph, Binary Search Tree(BST), AVL Tree, Priority Queue, Graph, Queue, Tree Multiset, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue, Stack. Benchmark compared with C++ STL. API aligned with ES6 and Java. Usability is comparable to Python", + "description": "Data Structures of Javascript & TypeScript. Heap, Binary Tree, Red Black Tree, Linked List, Deque, Trie, HashMap, Directed Graph, Undirected Graph, Binary Search Tree(BST), AVL Tree, Priority Queue, Graph, Queue, Tree Multiset, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue, Stack. Benchmark compared with C++ STL. API aligned with ES6 and Java.util. Usability is comparable to Python", "main": "dist/cjs/index.js", "module": "dist/mjs/index.js", "types": "dist/mjs/index.d.ts", diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index bbdbc02..c0999eb 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -248,6 +248,9 @@ export class BinaryTree = Bi const newNode = this.exemplarToNode(keyOrNodeOrEntry, value); if (newNode === undefined) return; + // TODO There are still some problems with the way duplicate nodes are handled + if (newNode !== null && this.has(newNode.key)) return undefined; + const _bfs = (root: N, newNode: N | null): N | undefined | null => { const queue = new Queue([root]); while (queue.size > 0) { @@ -325,17 +328,9 @@ export class BinaryTree = Bi * Space Complexity: O(1) */ - /** - * Time Complexity: O(k * n) "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted. - * Space Complexity: O(1) - * - * The `refill` function clears the current collection and adds new nodes, keys, or entries to it. - * @param nodesOrKeysOrEntries - The parameter `nodesOrKeysOrEntries` is an iterable object that can - * contain either `BTNodeExemplar` objects, keys, or entries. - */ - refill(nodesOrKeysOrEntries: Iterable>): void { + refill(nodesOrKeysOrEntries: Iterable>, values?: Iterable): void { this.clear(); - this.addMany(nodesOrKeysOrEntries); + this.addMany(nodesOrKeysOrEntries, values); } /** diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index a631fa7..6d2ebd2 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -359,31 +359,44 @@ export class BST = BSTNode = this.root, iterationType = this.iterationType): K { - // if (this._compare(0, 1) === CP.lt) return this.getRightMost(beginRoot, iterationType)?.key ?? 0; - // else if (this._compare(0, 1) === CP.gt) return this.getLeftMost(beginRoot, iterationType)?.key ?? 0; - // else return this.getRightMost(beginRoot, iterationType)?.key ?? 0; - // } + /** + * Time Complexity: O(n log n) - Adding each element individually in a balanced tree. + * Space Complexity: O(n) - Additional space is required for the sorted array. + */ + + /** + * Time Complexity: O(log n) - Average case for a balanced tree. + * Space Complexity: O(1) - Constant space is used. + * + * The `lastKey` function returns the key of the rightmost node in a binary tree, or the key of the + * leftmost node if the comparison result is greater than. + * @param {K | N | undefined} beginRoot - The `beginRoot` parameter is optional and can be of + * type `K`, `N`, or `undefined`. It represents the starting point for finding the last key in + * the binary tree. If not provided, it defaults to the root of the binary tree (`this.root`). + * @param iterationType - The `iterationType` parameter is used to specify the type of iteration to + * be performed. It can have one of the following values: + * @returns the key of the rightmost node in the binary tree if the comparison result is less than, + * the key of the leftmost node if the comparison result is greater than, and the key of the + * rightmost node otherwise. If no node is found, it returns 0. + */ + lastKey(beginRoot: BSTNodeKeyOrNode = this.root): K | undefined { + let current = this.ensureNode(beginRoot); + if (!current) return undefined; + + if (this._variant === BSTVariant.MIN) { + // For BSTVariant.MIN, find the rightmost node + while (current.right !== undefined) { + current = current.right; + } + } else { + // For BSTVariant.MAX, find the leftmost node + while (current.left !== undefined) { + current = current.left; + } + } + return current.key; + } + /** * Time Complexity: O(log n) - Average case for a balanced tree. @@ -636,7 +649,6 @@ export class BST = BSTNode extends IterableEntryBase { protected* _getIterator() { let node = this._head; while (node !== this._sentinel) { - yield <[K, V]>[node.key, node.value]; + yield [node.key, node.value] as [K, V]; node = node.next; } } diff --git a/src/data-structures/linked-list/doubly-linked-list.ts b/src/data-structures/linked-list/doubly-linked-list.ts index 4c4602a..b99c2ce 100644 --- a/src/data-structures/linked-list/doubly-linked-list.ts +++ b/src/data-structures/linked-list/doubly-linked-list.ts @@ -162,11 +162,11 @@ export class DoublyLinkedList extends IterableElementBase { * Time Complexity: O(1) * Space Complexity: O(1) * - * The `popLast()` function removes and returns the value of the last node in a doubly linked list. + * The `pollLast()` function removes and returns the value of the last node in a doubly linked list. * @returns The method is returning the value of the removed node (removedNode.value) if the list is not empty. If the * list is empty, it returns undefined. */ - popLast(): E | undefined { + pollLast(): E | undefined { return this.pop(); } @@ -206,11 +206,11 @@ export class DoublyLinkedList extends IterableElementBase { * Time Complexity: O(1) * Space Complexity: O(1) * - * The `popFirst()` function removes and returns the value of the first node in a doubly linked list. + * The `pollFirst()` function removes and returns the value of the first node in a doubly linked list. * @returns The method `shift()` returns the value of the node that is removed from the beginning of the doubly linked * list. */ - popFirst(): E | undefined { + pollFirst(): E | undefined { return this.shift(); } diff --git a/src/data-structures/linked-list/singly-linked-list.ts b/src/data-structures/linked-list/singly-linked-list.ts index c9bd8a2..b22bb2b 100644 --- a/src/data-structures/linked-list/singly-linked-list.ts +++ b/src/data-structures/linked-list/singly-linked-list.ts @@ -164,12 +164,12 @@ export class SinglyLinkedList extends IterableElementBase { * Time Complexity: O(n) - Linear time in the worst case, as it may need to traverse the list to find the last element. * Space Complexity: O(1) - Constant space. * - * The `popLast()` function removes and returns the value of the last element in a linked list, updating the head and tail + * The `pollLast()` function removes and returns the value of the last element in a linked list, updating the head and tail * pointers accordingly. * @returns The method `pop()` returns the value of the node that is being removed from the end of the linked list. If * the linked list is empty, it returns `undefined`. */ - popLast(): E | undefined { + pollLast(): E | undefined { return this.pop(); } @@ -202,10 +202,10 @@ export class SinglyLinkedList extends IterableElementBase { * Time Complexity: O(1) - Constant time, as it involves adjusting pointers at the head. * Space Complexity: O(1) - Constant space. * - * The `popFirst()` function removes and returns the value of the first node in a linked list. + * The `pollFirst()` function removes and returns the value of the first node in a linked list. * @returns The value of the node that is being removed from the beginning of the linked list. */ - popFirst(): E | undefined { + pollFirst(): E | undefined { return this.shift(); } diff --git a/src/data-structures/queue/deque.ts b/src/data-structures/queue/deque.ts index 18ad800..1b52bd9 100644 --- a/src/data-structures/queue/deque.ts +++ b/src/data-structures/queue/deque.ts @@ -120,10 +120,10 @@ export class Deque extends IterableElementBase { * Time Complexity: O(1) - Removes the last element. * Space Complexity: O(1) - Operates in-place. * - * The function "popLast" removes and returns the last element of an array. + * The function "pollLast" removes and returns the last element of an array. * @returns The last element of the array is being returned. */ - popLast(): E | undefined { + pollLast(): E | undefined { return this.pop(); } @@ -143,11 +143,11 @@ export class Deque extends IterableElementBase { * Time Complexity: O(1) - Removes the first element. * Space Complexity: O(1) - In-place operation. * - * The function "popFirst" removes and returns the first element of an array. - * @returns The method `popFirst()` is returning the first element of the array after removing it + * The function "pollFirst" removes and returns the first element of an array. + * @returns The method `pollFirst()` is returning the first element of the array after removing it * from the beginning. If the array is empty, it will return `undefined`. */ - popFirst(): E | undefined { + pollFirst(): E | undefined { return this.shift(); } @@ -947,10 +947,10 @@ export class ObjectDeque { * Time Complexity: O(1) * Space Complexity: O(1) * - * The function `popFirst()` removes and returns the first element in a data structure. + * The function `pollFirst()` removes and returns the first element in a data structure. * @returns The element of the first element in the data structure. */ - popFirst() { + pollFirst() { if (!this.size) return; const element = this.getFirst(); delete this.nodes[this.first]; @@ -984,10 +984,10 @@ export class ObjectDeque { * Time Complexity: O(1) * Space Complexity: O(1) * - * The `popLast()` function removes and returns the last element in a data structure. + * The `pollLast()` function removes and returns the last element in a data structure. * @returns The element that was removed from the data structure. */ - popLast() { + pollLast() { if (!this.size) return; const element = this.getLast(); delete this.nodes[this.last]; @@ -1039,4 +1039,4 @@ export class ObjectDeque { isEmpty() { return this.size <= 0; } -} \ No newline at end of file +} diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index ad47d46..1a3df3a 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -378,4 +378,4 @@ export class LinkedListQueue extends SinglyLinkedList { peek(): E | undefined { return this.getFirst(); } -} \ No newline at end of file +} diff --git a/src/types/data-structures/binary-tree/rb-tree.ts b/src/types/data-structures/binary-tree/rb-tree.ts index d7f7242..f9539df 100644 --- a/src/types/data-structures/binary-tree/rb-tree.ts +++ b/src/types/data-structures/binary-tree/rb-tree.ts @@ -7,4 +7,4 @@ export type RedBlackTreeNodeNested = RedBlackTreeNode> = RedBlackTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -export type RBTreeOptions = BSTOptions & {}; \ No newline at end of file +export type RBTreeOptions = BSTOptions & {}; diff --git a/src/types/data-structures/heap/heap.ts b/src/types/data-structures/heap/heap.ts index ed8deed..eec4d99 100644 --- a/src/types/data-structures/heap/heap.ts +++ b/src/types/data-structures/heap/heap.ts @@ -1,3 +1,3 @@ import { Comparator } from "../../common"; -export type HeapOptions = { comparator: Comparator } \ No newline at end of file +export type HeapOptions = { comparator: Comparator } diff --git a/src/types/data-structures/priority-queue/priority-queue.ts b/src/types/data-structures/priority-queue/priority-queue.ts index 524b762..0d534db 100644 --- a/src/types/data-structures/priority-queue/priority-queue.ts +++ b/src/types/data-structures/priority-queue/priority-queue.ts @@ -1,3 +1,3 @@ import { HeapOptions } from "../heap"; -export type PriorityQueueOptions = HeapOptions & {} \ No newline at end of file +export type PriorityQueueOptions = HeapOptions & {} diff --git a/test/unit/data-structures/linked-list/singly-linked-list.test.ts b/test/unit/data-structures/linked-list/singly-linked-list.test.ts index 8bff7f6..a6c0f3a 100644 --- a/test/unit/data-structures/linked-list/singly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/singly-linked-list.test.ts @@ -32,7 +32,7 @@ describe('SinglyLinkedList Operation Test', () => { list.push(3); const popped = list.pop(); expect(popped).toBe(3); - expect(list.popLast()).toBe(2); + expect(list.pollLast()).toBe(2); expect(list.toArray()).toEqual([1]); }); @@ -49,7 +49,7 @@ describe('SinglyLinkedList Operation Test', () => { list.push(3); const shifted = list.shift(); expect(shifted).toBe(1); - expect(list.popFirst()).toBe(2); + expect(list.pollFirst()).toBe(2); expect(list.toArray()).toEqual([3]); }); diff --git a/test/unit/data-structures/queue/deque.test.ts b/test/unit/data-structures/queue/deque.test.ts index 808f5f1..57bf000 100644 --- a/test/unit/data-structures/queue/deque.test.ts +++ b/test/unit/data-structures/queue/deque.test.ts @@ -22,13 +22,13 @@ describe('Deque Tests', () => { it('should delete elements from the beginning and end', () => { deque.addFirst(1); deque.addLast(2); - deque.popFirst(); - deque.popLast(); + deque.pollFirst(); + deque.pollLast(); expect(deque.isEmpty()).toBe(true); }); it('should handle edge case when removing from an empty deque', () => { - const result = deque.popFirst(); + const result = deque.pollFirst(); expect(result).toBeUndefined(); }); @@ -40,18 +40,18 @@ describe('Deque Tests', () => { it('should handle adding and removing elements alternately', () => { deque.addFirst(1); - expect(deque.popFirst()).toBe(1); + expect(deque.pollFirst()).toBe(1); deque.addLast(2); - expect(deque.popLast()).toBe(2); + expect(deque.pollLast()).toBe(2); expect(deque.isEmpty()).toBe(true); }); it('should handle adding and removing elements in a cyclic manner', () => { deque.addFirst(1); deque.addLast(2); - expect(deque.popFirst()).toBe(1); + expect(deque.pollFirst()).toBe(1); deque.addFirst(3); - expect(deque.popLast()).toBe(2); + expect(deque.pollLast()).toBe(2); expect(deque.size).toBe(1); }); // Add more test cases as needed @@ -75,13 +75,13 @@ describe('Deque Tests', () => { // it('should delete elements from the beginning and end', () => { // objectDeque.addFirst('one'); // objectDeque.addLast('two'); - // objectDeque.popFirst(); - // objectDeque.popLast(); + // objectDeque.pollFirst(); + // objectDeque.pollLast(); // expect(objectDeque.isEmpty()).toBe(true); // }); // // it('should handle edge case when removing from an empty deque', () => { - // const result = objectDeque.popFirst(); + // const result = objectDeque.pollFirst(); // expect(result).toBeUndefined(); // }); // @@ -136,8 +136,8 @@ describe('Deque', () => { deque.addFirst(1); deque.addLast(2); - const firstElement = deque.popFirst(); - const lastElement = deque.popLast(); + const firstElement = deque.pollFirst(); + const lastElement = deque.pollLast(); expect(deque.size).toBe(0); expect(firstElement).toBe(1); @@ -166,7 +166,7 @@ describe('Deque', () => { deque.addLast(1); expect(deque.isEmpty()).toBe(false); - deque.popFirst(); + deque.pollFirst(); expect(deque.isEmpty()).toBe(true); }); }); @@ -200,7 +200,7 @@ describe('Deque', () => { // deque.addLast(1); // deque.addLast(2); // -// const removedElement = deque.popFirst(); +// const removedElement = deque.pollFirst(); // // expect(deque.size).toBe(1); // expect(removedElement).toBe(1); @@ -211,7 +211,7 @@ describe('Deque', () => { // deque.addLast(1); // deque.addLast(2); // -// const removedElement = deque.popFirst(); +// const removedElement = deque.pollFirst(); // // expect(deque.size).toBe(1); // expect(removedElement).toBe(1);