refactor: Rewrite the lastKey method. The BinaryTree.add method filters out duplicate additions. Rename popLast and popFirst to pollLast and pollFirst.

This commit is contained in:
Revone 2023-12-07 19:34:20 +08:00
parent aff29b3568
commit a02a9a94d2
14 changed files with 85 additions and 78 deletions

View file

@ -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

View file

@ -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",

View file

@ -248,6 +248,9 @@ export class BinaryTree<K = any, V = any, N extends BinaryTreeNode<K, V, N> = 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<N>([root]);
while (queue.size > 0) {
@ -325,17 +328,9 @@ export class BinaryTree<K = any, V = any, N extends BinaryTreeNode<K, V, N> = 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<BTNodeExemplar<K, V, N>>): void {
refill(nodesOrKeysOrEntries: Iterable<BTNodeExemplar<K, V, N>>, values?: Iterable<V | undefined>): void {
this.clear();
this.addMany(nodesOrKeysOrEntries);
this.addMany(nodesOrKeysOrEntries, values);
}
/**

View file

@ -359,31 +359,44 @@ export class BST<K = any, V = any, N extends BSTNode<K, V, N> = BSTNode<K, V, BS
}
// /**
// * 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<K,N> = 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<K, N> = 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<K = any, V = any, N extends BSTNode<K, V, N> = BSTNode<K, V, BS
if (l <= r) {
const m = l + Math.floor((r - l) / 2);
const midNode = sorted[m];
debugger;
this.add([midNode.key, midNode.value]);
stack.push([m + 1, r]);
stack.push([l, m - 1]);

View file

@ -625,7 +625,7 @@ export class LinkedHashMap<K = any, V = any> extends IterableEntryBase<K, V> {
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;
}
}

View file

@ -162,11 +162,11 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
* 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<E = any> extends IterableElementBase<E> {
* 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();
}

View file

@ -164,12 +164,12 @@ export class SinglyLinkedList<E = any> extends IterableElementBase<E> {
* 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<E = any> extends IterableElementBase<E> {
* 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();
}

View file

@ -120,10 +120,10 @@ export class Deque<E> extends IterableElementBase<E> {
* 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<E> extends IterableElementBase<E> {
* 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<E = number> {
* 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<E = number> {
* 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<E = number> {
isEmpty() {
return this.size <= 0;
}
}
}

View file

@ -378,4 +378,4 @@ export class LinkedListQueue<E = any> extends SinglyLinkedList<E> {
peek(): E | undefined {
return this.getFirst();
}
}
}

View file

@ -7,4 +7,4 @@ export type RedBlackTreeNodeNested<K, V> = RedBlackTreeNode<K, V, RedBlackTreeNo
export type RedBlackTreeNested<K, V, N extends RedBlackTreeNode<K, V, N>> = RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, RedBlackTree<K, V, N, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type RBTreeOptions<K> = BSTOptions<K> & {};
export type RBTreeOptions<K> = BSTOptions<K> & {};

View file

@ -1,3 +1,3 @@
import { Comparator } from "../../common";
export type HeapOptions<T> = { comparator: Comparator<T> }
export type HeapOptions<T> = { comparator: Comparator<T> }

View file

@ -1,3 +1,3 @@
import { HeapOptions } from "../heap";
export type PriorityQueueOptions<T> = HeapOptions<T> & {}
export type PriorityQueueOptions<T> = HeapOptions<T> & {}

View file

@ -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]);
});

View file

@ -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);