Refactor: Standardize addition and removal methods for all sequential data structures to push, pop, shift, unshift.

This commit is contained in:
Revone 2024-01-09 12:04:50 +08:00
parent 70882d24fc
commit 4747839d88
14 changed files with 285 additions and 447 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.50.3](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
## [v1.50.4](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
### Changes

114
README.md
View file

@ -1,6 +1,5 @@
# data-structure-typed
![npm](https://img.shields.io/npm/dm/data-structure-typed)
![GitHub contributors](https://img.shields.io/github/contributors/zrwusa/data-structure-typed)
![npm package minimized gzipped size (select exports)](https://img.shields.io/bundlejs/size/data-structure-typed)
@ -17,7 +16,8 @@
## Why
Do you envy C++ with [STL]() (std::), Python with [collections](), and Java with [java.util]() ? Well, no need to envy
anymore! JavaScript and TypeScript now have [data-structure-typed]().**`Benchmark`** compared with C++ STL. **`API standards`** aligned with ES6 and Java. **`Usability`** is comparable to Python
anymore! JavaScript and TypeScript now have [data-structure-typed]().**`Benchmark`** compared with C++ STL. *
*`API standards`** aligned with ES6 and Java. **`Usability`** is comparable to Python
[//]: # (![Branches](https://img.shields.io/badge/branches-55.47%25-red.svg?style=flat))
@ -28,13 +28,15 @@ anymore! JavaScript and TypeScript now have [data-structure-typed]().**`Benchmar
[//]: # (![Lines](https://img.shields.io/badge/lines-68.6%25-red.svg?style=flat))
### We provide data structures that are not available in JS/TS
### Data structures available
Heap, Binary Tree, Red Black Tree, Linked List, Deque, Trie, Directed Graph, Undirected Graph, BST, AVL Tree, Priority Queue, Queue, Tree Multiset.
We provide data structures that are not available in JS/TS
Heap, Binary Tree, Red Black Tree, Linked List, Deque, Trie, Directed Graph, Undirected Graph, BST, AVL Tree, Priority
Queue, Queue, Tree Multiset.
### Performance
### Performance surpasses that of native JS/TS
Performance surpasses that of native JS/TS
<table style="display: table; width:100%; table-layout: fixed;">
<thead>
@ -99,6 +101,53 @@ Heap, Binary Tree, Red Black Tree, Linked List, Deque, Trie, Directed Graph, Und
</tbody>
</table>
### Conciseness and uniformity
In Java.utils, you need to memorize a table for all sequential data structures(Queue, Deque, LinkedList),
<table>
<thead>
<tr>
<th>Operation</th>
<th>Java ArrayList</th>
<th>Java Queue</th>
<th>Java ArrayDeque</th>
<th>Java LinkedList</th>
</tr>
</thead>
<tbody>
<tr>
<td>push</td>
<td>add</td>
<td>offer</td>
<td>push</td>
<td>push</td>
</tr>
<tr>
<td>pop</td>
<td>remove</td>
<td>poll</td>
<td>removeLast</td>
<td>removeLast</td>
</tr>
<tr>
<td>shift</td>
<td>remove</td>
<td>poll</td>
<td>removeFirst</td>
<td>removeFirst</td>
</tr>
<tr>
<td>unshift</td>
<td>add(0, element)</td>
<td>offerFirst</td>
<td>unshift</td>
<td>unshift</td>
</tr>
</tbody>
</table>
whereas in our data-structure-typed, you **only** need to remember four methods: `push`, `pop`, `shift`, and `unshift` for all sequential data structures.
## Installation and Usage
### npm
@ -155,7 +204,7 @@ our [visual tool](https://github.com/zrwusa/vivid-algorithm)
#### TS
```ts
import {RedBlackTree} from 'data-structure-typed';
import { RedBlackTree } from 'data-structure-typed';
const rbTree = new RedBlackTree<number>();
rbTree.addMany([11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5])
@ -177,7 +226,7 @@ rbTree.print()
#### JS
```js
import {RedBlackTree} from 'data-structure-typed';
import { RedBlackTree } from 'data-structure-typed';
const rbTree = new RedBlackTree();
rbTree.addMany([11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5])
@ -204,31 +253,31 @@ const orgStrArr = ["trie", "trial", "trick", "trip", "tree", "trend", "triangle"
const entries = [[6, "6"], [1, "1"], [2, "2"], [7, "7"], [5, "5"], [3, "3"], [4, "4"], [9, "9"], [8, "8"]];
const queue = new Queue(orgArr);
queue.print();
queue.print();
// [6, 1, 2, 7, 5, 3, 4, 9, 8]
const deque = new Deque(orgArr);
deque.print();
deque.print();
// [6, 1, 2, 7, 5, 3, 4, 9, 8]
const sList = new SinglyLinkedList(orgArr);
sList.print();
sList.print();
// [6, 1, 2, 7, 5, 3, 4, 9, 8]
const dList = new DoublyLinkedList(orgArr);
dList.print();
dList.print();
// [6, 1, 2, 7, 5, 3, 4, 9, 8]
const stack = new Stack(orgArr);
stack.print();
stack.print();
// [6, 1, 2, 7, 5, 3, 4, 9, 8]
const minHeap = new MinHeap(orgArr);
minHeap.print();
minHeap.print();
// [1, 5, 2, 7, 6, 3, 4, 9, 8]
const maxPQ = new MaxPriorityQueue(orgArr);
maxPQ.print();
maxPQ.print();
// [9, 8, 4, 7, 5, 2, 3, 1, 6]
const biTree = new BinaryTree(entries);
@ -284,7 +333,7 @@ treeMulti.print();
// 7 9
const hm = new HashMap(entries);
hm.print()
hm.print()
// [[6, "6"], [1, "1"], [2, "2"], [7, "7"], [5, "5"], [3, "3"], [4, "4"], [9, "9"], [8, "8"]]
const rbTreeH = new RedBlackTree(hm);
@ -298,7 +347,7 @@ rbTreeH.print();
// 7 9
const pq = new MinPriorityQueue(orgArr);
pq.print();
pq.print();
// [1, 5, 2, 7, 6, 3, 4, 9, 8]
const bst1 = new BST(pq);
@ -312,7 +361,7 @@ bst1.print();
// 4 9
const dq1 = new Deque(orgArr);
dq1.print();
dq1.print();
// [6, 1, 2, 7, 5, 3, 4, 9, 8]
const rbTree1 = new RedBlackTree(dq1);
rbTree1.print();
@ -326,13 +375,13 @@ rbTree1.print();
const trie2 = new Trie(orgStrArr);
trie2.print();
trie2.print();
// ['trie', 'trial', 'triangle', 'trick', 'trip', 'tree', 'trend', 'track', 'trace', 'transmit']
const heap2 = new Heap(trie2, { comparator: (a, b) => Number(a) - Number(b) });
heap2.print();
heap2.print();
// ['transmit', 'trace', 'tree', 'trend', 'track', 'trial', 'trip', 'trie', 'trick', 'triangle']
const dq2 = new Deque(heap2);
dq2.print();
dq2.print();
// ['transmit', 'trace', 'tree', 'trend', 'track', 'trial', 'trip', 'trie', 'trick', 'triangle']
const entries2 = dq2.map((el, i) => [i, el]);
const avl2 = new AVLTree(entries2);
@ -349,7 +398,7 @@ avl2.print();
### Binary Search Tree (BST) snippet
```ts
import {BST, BSTNode} from 'data-structure-typed';
import { BST, BSTNode } from 'data-structure-typed';
const bst = new BST<number>();
bst.add(11);
@ -381,7 +430,7 @@ bst.print()
// \
// 7
const objBST = new BST<number, {height: number, age: number}>();
const objBST = new BST<number, { height: number, age: number }>();
objBST.add(11, { "name": "Pablo", "age": 15 });
objBST.add(3, { "name": "Kirk", "age": 1 });
@ -410,7 +459,7 @@ objBST.delete(11);
### AVLTree snippet
```ts
import {AVLTree} from 'data-structure-typed';
import { AVLTree } from 'data-structure-typed';
const avlTree = new AVLTree<number>();
avlTree.addMany([11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5])
@ -422,7 +471,7 @@ avlTree.isAVLBalanced(); // true
### Directed Graph simple snippet
```ts
import {DirectedGraph} from 'data-structure-typed';
import { DirectedGraph } from 'data-structure-typed';
const graph = new DirectedGraph<string>();
@ -451,7 +500,7 @@ const topologicalOrderKeys = graph.topologicalSort(); // ['A', 'B', 'C']
### Undirected Graph snippet
```ts
import {UndirectedGraph} from 'data-structure-typed';
import { UndirectedGraph } from 'data-structure-typed';
const graph = new UndirectedGraph<string>();
graph.addVertex('A');
@ -885,7 +934,10 @@ Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.key) // ['A', 'B', '
## Software Engineering Design Standards
We strictly adhere to computer science theory and software development standards. Our LinkedList is designed in the traditional sense of the LinkedList data structure, and we refrain from substituting it with a Deque solely for the purpose of showcasing performance test data. However, we have also implemented a Deque based on a dynamic array concurrently.
We strictly adhere to computer science theory and software development standards. Our LinkedList is designed in the
traditional sense of the LinkedList data structure, and we refrain from substituting it with a Deque solely for the
purpose of showcasing performance test data. However, we have also implemented a Deque based on a dynamic array
concurrently.
<table style="display: table; width:100%; table-layout: fixed;">
@ -935,7 +987,6 @@ We strictly adhere to computer science theory and software development standards
</tr>
</table>
## Benchmark
[//]: # (No deletion!!! Start of Replace Section)
@ -982,9 +1033,8 @@ We strictly adhere to computer science theory and software development standards
[//]: # (No deletion!!! End of Replace Section)
## supported module system
Now you can use it in Node.js and browser environments
CommonJS:**`require export.modules =`**
@ -1002,19 +1052,21 @@ Copy the line below into the head tag in an HTML document.
#### development
```html
<script src='https://cdn.jsdelivr.net/npm/data-structure-typed/dist/umd/data-structure-typed.js'></script>
```
#### production
```html
<script src='https://cdn.jsdelivr.net/npm/data-structure-typed/dist/umd/data-structure-typed.min.js'></script>
```
Copy the code below into the script tag of your HTML, and you're good to go with your development.
```js
const {Heap} = dataStructureTyped;
const { Heap } = dataStructureTyped;
const {
BinaryTree, Graph, Queue, Stack, PriorityQueue, BST, Trie, DoublyLinkedList,
AVLTree, MinHeap, SinglyLinkedList, DirectedGraph, TreeMultiMap,

View file

@ -45,7 +45,7 @@
### Use of Commonly Understood Industry Standard Naming
- `enqueue`, `dequeue`, `push`, `pop`, `poll`, `addLast`, `addFirst`, `pollFirst`, `pollLast`, `isEmpty`, `clear`, `print`, `clone`.
- `enqueue`, `dequeue`, `push`, `pop`, `poll`, `push`, `unshift`, `shift`, `pop`, `isEmpty`, `clear`, `print`, `clone`.
### Implementation of Customizable Features Whenever Possible
@ -53,4 +53,4 @@
### Comprehensive Documentation
- The documentation not only explains the purpose of methods but also annotates time and space complexity across the entire series.
- The documentation not only explains the purpose of methods but also annotates time and space complexity across the entire series.

81
SPECIFICATION_zh-CN.md Normal file
View file

@ -0,0 +1,81 @@
[NPM](https://www.npmjs.com/package/data-structure-typed)
[Github](https://github.com/zrwusa/data-structure-typed)
## Pain Points Addressed
### Enhancing the Performance of Simulated Data Structures in JS/TS
- `Queue`: While many resort to using Arrays to simulate Queues and Deques, the time complexity of Array.shift is O(n). We have tackled this challenge by implementing a Queue and Deque with O(1) time complexity for enqueue and dequeue operations.
- `HashMap`: Opting for a pure HashMap over the built-in Map (technically a LinkedHashMap) can boost algorithmic speed. However, the performance is compromised due to the necessity of considering insertion order. We have independently implemented an optimized HashMap.
- `Stack`: In JS, simulating a Stack with an Array is acceptable, and its performance is on par with a genuine Stack.
### Introducing Missing Native Data Structures in JS/TS
- `Heap / Priority Queue`: Algorithms with O(log n) time complexity have been pivotal in improving efficiency since the dawn of computers. A Heap supports insertion, deletion, and search with O(log n) time complexity, coupled with the ability to obtain the minimum / maximum value in O(1) time.
- `Red Black Tree`: Developers well-versed in databases, file systems, Linux virtual memory management, and network routing tables often have a nuanced understanding of Red-Black Trees. It stands out as the least operation-intensive among all balanced binary search trees, offering optimal performance balance in CRUD operations.
- `Linked List`: In scenarios where insertion or deletion of elements with O(1) time complexity is required at a specific index in an ordered collection, JS lacks a provided data structure. Hence, the need for a LinkedList to implement this functionality.
- `Trie`: Efficient for fast string queries and space-efficient string storage, yet not commonly found in the standard libraries of most programming languages.
- `Graph`: This data structure is not commonly found in the standard libraries of most languages, making it a non-issue in JS.
## Advantages
### Performance:
- The performance of some ours data structures has surpassed JS's built-in data structures (`Queue`, `Deque`, `HashMap`), while most are comparable to or even surpass those in other languages. Some are still undergoing refinement (`Graph`, `AVL Tree`).
### Uniformity
- 1. Implementation or constraint of `forEach`, `filter`, `map`, `every`, `some`, `reduce`, `find`, `has`, `hasValue`, `get`, `print`, `isEmpty`, `clear`, `clone` methods in the base class.
- 2. Use of generators to uniformly implement `[Symbol.iterator]`, `entries`, `keys`, `values`. Delaying iterator execution prevents performance loss and provides control during traversal.
- 3. All deletion methods uniformly use the widely adopted `delete` in ES6, while addition methods uniformly use `add`. Compatibility with some specifications in Java.
- 4. The first parameter for all constructors is data, and the second parameter is configuration, maintaining uniformity. The first parameter accepts any iterable type for seamless conversion between data structures.
- 5. Uniform return types, for example, the `add` method consistently returns a boolean.
### Convenience and Simplicity of APIs
- Inspired by ES6, Java, ESNext, TypeScript, Python, featuring methods like `forEach`, `filter`, `map`, `every`, `some`, `reduce`, `find`, `has`, `hasValue` and `get`.
### Use of Commonly Understood Industry Standard Naming
- `enqueue`, `dequeue`, `push`, `pop`, `poll`, `push`, `unshift`, `shift`, `pop`, `isEmpty`, `clear`, `print`, `clone`.
### Implementation of Customizable Features Whenever Possible
- Such as providing callback functions (lambda expressions) for all traversal methods.
### Comprehensive Documentation
- The documentation not only explains the purpose of methods but also annotates time and space complexity across the entire series.
像getter和setter是优于Java的getXxx和setXxx
Java中
添加元素(类似 push
add(E element): 将元素添加到列表的末尾。
add(int index, E element): 在指定的索引位置插入元素。
移除元素(类似 pop
remove(int index): 移除指定索引位置的元素。
获取并移除首个元素(类似 shift
remove(0): 移除索引为0的元素。
在首位插入元素(类似 unshift
add(0, E element): 在指定索引0处插入元素。
大多数程序员更喜欢JS中的Array的push, pop, shift, unshift。
原因有以下几点:
命名更直观。JS中的push, pop, shift, unshift的命名更加直观可以直接理解其操作的含义。而Java中的add和remove的命名则比较抽象需要一定的理解才能理解其操作的含义。
使用更方便。JS中的push, pop, shift, unshift的操作更加方便只需要一个参数即可完成操作。而Java中的add和remove的操作则需要两个参数第一个参数指定操作的索引第二个参数指定操作的值。
性能更高。JS中的push, pop, shift, unshift的性能更高因为其操作只需要修改数组的长度即可完成。而Java中的add和remove的性能则较低因为其操作需要移动数组中的元素。

View file

@ -68,7 +68,7 @@
### 使用通俗易懂业界常用命名
- `enqueue`, `dequeue`, `push`, `pop`, `poll`, `addLast`, `addFirst`, `pollFirst`, `pollLast`, `isEmpty`, `clear`, `print`, `clone`
- `enqueue`, `dequeue`, `push`, `pop`, `poll`, `push`, `unshift`, `shift`, `pop`, `isEmpty`, `clear`, `print`, `clone`
### 尽量实现可定制化功能

View file

@ -194,14 +194,13 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
*/
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The push function adds a new node with the given value to the end of the doubly linked list.
* @param {E} value - The value to be added to the linked list.
* The push function adds a new element to the end of a doubly linked list.
* @param {E} element - The "element" parameter represents the value that you want to add to the
* doubly linked list.
* @returns The `push` method is returning a boolean value, `true`.
*/
push(value: E): boolean {
const newNode = new DoublyLinkedListNode(value);
push(element: E): boolean {
const newNode = new DoublyLinkedListNode(element);
if (!this.head) {
this._head = newNode;
this._tail = newNode;
@ -220,12 +219,8 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
*/
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The `pop()` 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.
* The `pop()` function removes and returns the value of the last element in a linked list.
* @returns The method is returning the value of the removed node.
*/
pop(): E | undefined {
if (!this.tail) return undefined;
@ -247,12 +242,8 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
*/
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The `shift()` 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.
* The `shift()` function removes and returns the value of the first element in a doubly linked list.
* @returns The value of the removed node.
*/
shift(): E | undefined {
if (!this.head) return undefined;
@ -274,15 +265,13 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
*/
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The unshift function adds a new node with the given value to the beginning of a doubly linked list.
* @param {E} value - The `value` parameter represents the value of the new node that will be added to the beginning of the
* doubly linked list.
* The unshift function adds a new element to the beginning of a doubly linked list.
* @param {E} element - The "element" parameter represents the value of the element that you want to
* add to the beginning of the doubly linked list.
* @returns The `unshift` method is returning a boolean value, `true`.
*/
unshift(value: E): boolean {
const newNode = new DoublyLinkedListNode(value);
unshift(element: E): boolean {
const newNode = new DoublyLinkedListNode(element);
if (!this.head) {
this._head = newNode;
this._tail = newNode;
@ -811,73 +800,6 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
return mappedList;
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The addLast function adds a new node with the given value to the end of the doubly linked list.
* @param {E} value - The value to be added to the linked list.
*/
addLast(value: E): boolean {
return this.push(value);
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* 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.
*/
pollLast(): E | undefined {
return this.pop();
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* 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.
*/
pollFirst(): E | undefined {
return this.shift();
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The addFirst function adds a new node with the given value to the beginning of a doubly linked list.
* @param {E} value - The `value` parameter represents the value of the new node that will be added to the beginning of the
* doubly linked list.
*/
addFirst(value: E): void {
this.unshift(value);
}
/**
* The function returns an iterator that iterates over the values of a linked list.
*/

View file

@ -93,6 +93,24 @@ export class SinglyLinkedList<E = any> extends IterableElementBase<E> {
return this._tail;
}
/**
* The above function returns the value of the first element in a linked list, or undefined if the
* list is empty.
* @returns The value of the first node in the linked list, or undefined if the linked list is empty.
*/
get first(): E | undefined {
return this.head?.value;
}
/**
* The function returns the value of the last element in a linked list, or undefined if the list is
* empty.
* @returns The value of the last node in the linked list, or undefined if the linked list is empty.
*/
get last(): E | undefined {
return this.tail?.value;
}
protected _size: number = 0;
/**
@ -130,20 +148,19 @@ export class SinglyLinkedList<E = any> extends IterableElementBase<E> {
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
* Constant time, as it involves basic pointer adjustments.
* Constant space, as it only creates a new node.
*/
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The `push` function adds a new node with the given value to the end of a singly linked list.
* @param {E} value - The "value" parameter represents the value that you want to add to the linked list. It can be of
* any type (E) as specified in the generic type declaration of the class or function.
* The push function adds a new element to the end of a singly linked list.
* @param {E} element - The "element" parameter represents the value of the element that you want to
* add to the linked list.
* @returns The `push` method is returning a boolean value, `true`.
*/
push(value: E): boolean {
const newNode = new SinglyLinkedListNode(value);
push(element: E): boolean {
const newNode = new SinglyLinkedListNode(element);
if (!this.head) {
this._head = newNode;
this._tail = newNode;
@ -155,23 +172,6 @@ export class SinglyLinkedList<E = any> extends IterableElementBase<E> {
return true;
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The `push` function adds a new node with the given value to the end of a singly linked list.
* @param {E} value - The "value" parameter represents the value that you want to add to the linked list. It can be of
* any type (E) as specified in the generic type declaration of the class or function.
*/
addLast(value: E): boolean {
return this.push(value);
}
/**
* Time Complexity: O(n)
* Space Complexity: O(1)
@ -182,10 +182,9 @@ export class SinglyLinkedList<E = any> extends IterableElementBase<E> {
* Time Complexity: O(n)
* Space Complexity: O(1)
*
* The `pop()` 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`.
* The `pop` function removes and returns the value of the last element in a linked list.
* @returns The method is returning the value of the element that is being popped from the end of the
* list.
*/
pop(): E | undefined {
if (!this.head) return undefined;
@ -208,24 +207,6 @@ export class SinglyLinkedList<E = any> extends IterableElementBase<E> {
return value;
}
/**
* Time Complexity: O(n)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(n)
* Space Complexity: O(1)
*
* 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`.
*/
pollLast(): E | undefined {
return this.pop();
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
@ -235,8 +216,8 @@ export class SinglyLinkedList<E = any> extends IterableElementBase<E> {
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The `shift()` 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.
* The `shift()` function removes and returns the value of the first element in a linked list.
* @returns The value of the removed node.
*/
shift(): E | undefined {
if (!this.head) return undefined;
@ -255,28 +236,13 @@ export class SinglyLinkedList<E = any> extends IterableElementBase<E> {
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* 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.
* The unshift function adds a new element to the beginning of a singly linked list.
* @param {E} element - The "element" parameter represents the value of the element that you want to
* add to the beginning of the singly linked list.
* @returns The `unshift` method is returning a boolean value, `true`.
*/
pollFirst(): E | undefined {
return this.shift();
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The unshift function adds a new node with the given value to the beginning of a singly linked list.
* @param {E} value - The parameter "value" represents the value of the new node that will be added to the beginning of the
* linked list.
*/
unshift(value: E): boolean {
const newNode = new SinglyLinkedListNode(value);
unshift(element: E): boolean {
const newNode = new SinglyLinkedListNode(element);
if (!this.head) {
this._head = newNode;
this._tail = newNode;
@ -288,27 +254,9 @@ export class SinglyLinkedList<E = any> extends IterableElementBase<E> {
return true;
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The addFirst function adds a new node with the given value to the beginning of a singly linked list.
* @param {E} value - The parameter "value" represents the value of the new node that will be added to the beginning of the
* linked list.
*/
addFirst(value: E): boolean {
return this.unshift(value);
}
/**
* Time Complexity: O(n)
* Space Complexity: O(1)
* Linear time, where n is the index, as it may need to traverse the list to find the desired node.
*/
/**

View file

@ -811,73 +811,6 @@ export class Deque<E> extends IterableElementBase<E> {
return newDeque;
}
/**
* Time Complexity: Amortized O(1) - Similar to push, resizing leads to O(n).
* Space Complexity: O(n) - Due to potential resizing.
*/
/**
* Time Complexity: Amortized O(1) - Similar to push, resizing leads to O(n).
* Space Complexity: O(n) - Due to potential resizing.
*
* The addLast function adds an element to the end of an array.
* @param {E} element - The element parameter represents the element that you want to add to the end of the
* data structure.
*/
addLast(element: E): boolean {
return this.push(element);
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The function "pollLast" removes and returns the last element of an array.
* @returns The last element of the array is being returned.
*/
pollLast(): E | undefined {
return this.pop();
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
* /
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The "addFirst" function adds an element to the beginning of an array.
* @param {E} element - The parameter "element" represents the element that you want to add to the
* beginning of the data structure.
*/
addFirst(element: E): boolean {
return this.unshift(element);
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
* /
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* 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`.
*/
pollFirst(): E | undefined {
return this.shift();
}
/**
* Time Complexity: O(n)
* Space Complexity: O(1)

View file

@ -178,72 +178,6 @@ export class Queue<E = any> extends IterableElementBase<E> {
return spliced.length === 1;
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The `peek` function returns the first element of the array `_elements` if it exists, otherwise it returns `undefined`.
* @returns The `peek()` method returns the first element of the data structure, represented by the `_elements` array at
* the `_offset` index. If the data structure is empty (size is 0), it returns `undefined`.
*/
peek(): E | undefined {
return this.first;
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The `peekLast` function returns the last element in an array-like data structure, or undefined if the structure is empty.
* @returns The method `peekLast()` returns the last element of the `_elements` array if the array is not empty. If the
* array is empty, it returns `undefined`.
*/
peekLast(): E | undefined {
return this.last;
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The enqueue function adds a value to the end of a queue.
* @param {E} value - The value parameter represents the value that you want to add to the queue.
*/
enqueue(value: E): boolean {
return this.push(value);
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The `dequeue` function removes and returns the first element from a queue, or returns undefined if the queue is empty.
* @returns The method is returning a value of type E or undefined.
*/
dequeue(): E | undefined {
return this.shift();
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
@ -411,38 +345,6 @@ export class Queue<E = any> extends IterableElementBase<E> {
* 4. Frequent Enqueuing and Dequeuing Operations: If your application involves frequent enqueuing and dequeuing operations and is less concerned with random access, then LinkedListQueue is a good choice.
*/
export class LinkedListQueue<E = any> extends SinglyLinkedList<E> {
/**
* The `get first` function returns the value of the head node in a linked list, or `undefined` if the list is empty.
* @returns The `get first()` method is returning the value of the `head` node if it exists, otherwise it returns `undefined`.
*/
get first(): E | undefined {
return this.head?.value;
}
/**
* The enqueue function adds a value to the end of an array.
* @param {E} value - The value parameter represents the value that you want to add to the queue.
*/
enqueue(value: E): boolean {
return this.push(value);
}
/**
* The `dequeue` function removes and returns the first element from a queue, or returns undefined if the queue is empty.
* @returns The method is returning the element at the front of the queue, or undefined if the queue is empty.
*/
dequeue(): E | undefined {
return this.shift();
}
/**
* The `peek` function returns the value of the head node in a linked list, or `undefined` if the list is empty.
* @returns The `peek()` method is returning the value of the `head` node if it exists, otherwise it returns `undefined`.
*/
peek(): E | undefined {
return this.first;
}
/**
* Time Complexity: O(n)
* Space Complexity: O(n)

View file

@ -39,12 +39,12 @@ describe('DoublyLinkedList Operation Test', () => {
it('should clone', function () {
const dList = new DoublyLinkedList<string>();
dList.addLast('1');
dList.addLast('6');
dList.addLast('2');
dList.addLast('0');
dList.addLast('5');
dList.addLast('9');
dList.push('1');
dList.push('6');
dList.push('2');
dList.push('0');
dList.push('5');
dList.push('9');
dList.delete('2');
expect([...dList]).toEqual(['1', '6', '0', '5', '9']);
const cloned = dList.clone();

View file

@ -32,7 +32,7 @@ describe('SinglyLinkedList Operation Test', () => {
list.push(3);
const popped = list.pop();
expect(popped).toBe(3);
expect(list.pollLast()).toBe(2);
expect(list.pop()).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.pollFirst()).toBe(2);
expect(list.shift()).toBe(2);
expect(list.toArray()).toEqual([3]);
});
@ -62,7 +62,7 @@ describe('SinglyLinkedList Operation Test', () => {
describe('unshift', () => {
it('should add elements to the beginning of the list', () => {
list.unshift(1);
list.addFirst(2);
list.unshift(2);
expect(list.toArray()).toEqual([2, 1]);
});
});
@ -350,12 +350,12 @@ describe('SinglyLinkedList Operation Test', () => {
it('should clone', function () {
const sList = new SinglyLinkedList<string>();
sList.addLast('1');
sList.addLast('6');
sList.addLast('2');
sList.addLast('0');
sList.addLast('5');
sList.addLast('9');
sList.push('1');
sList.push('6');
sList.push('2');
sList.push('0');
sList.push('5');
sList.push('9');
sList.delete('2');
expect([...sList]).toEqual(['1', '6', '0', '5', '9']);
const cloned = sList.clone();
@ -478,7 +478,7 @@ describe('SinglyLinkedList', () => {
});
it('should map the list', () => {
list.addLast(1);
list.push(1);
list.push(2);
list.push(3);
expect(list.map(value => value * 2).toArray()).toEqual([2, 4, 6]);

View file

@ -65,21 +65,21 @@ describe('SkipList Test2', () => {
skipList.add(4, 'Four');
});
it('getFirst() should return the getFirst element', () => {
it('first() should return the first element', () => {
expect(skipList.first).toBe('One');
});
it('getLast() should return the getLast element', () => {
it('last() should return the last element', () => {
expect(skipList.last).toBe('Four');
});
it('higher(key) should return the getFirst element greater than the given key', () => {
it('higher(key) should return the first element greater than the given key', () => {
expect(skipList.higher(2)).toBe('Three');
expect(skipList.higher(3)).toBe('Four');
expect(skipList.higher(4)).toBeUndefined();
});
it('lower(key) should return the getLast element less than the given key', () => {
it('lower(key) should return the last element less than the given key', () => {
expect(skipList.lower(2)).toBe('One');
expect(skipList.lower(1)).toBe(undefined);
});

View file

@ -52,12 +52,12 @@ describe('Deque - Basic Operations', () => {
it('should clone', function () {
const deque = new Deque<string>();
deque.addLast('1');
deque.addLast('6');
deque.addLast('2');
deque.addLast('0');
deque.addLast('5');
deque.addLast('9');
deque.push('1');
deque.push('6');
deque.push('2');
deque.push('0');
deque.push('5');
deque.push('9');
expect(deque.size).toBe(6);
deque.delete('2');
expect(deque.size).toBe(5);
@ -70,7 +70,7 @@ describe('Deque - Basic Operations', () => {
expect([...deque]).toEqual(['1', '6', '0', '9']);
expect([...cloned]).toEqual(['1', '6', '0', '5', '9']);
expect(cloned.size).toBe(5);
cloned.addLast('8');
cloned.push('8');
expect(cloned.size).toBe(6);
cloned.delete('6');
expect(cloned.size).toBe(5);
@ -239,52 +239,52 @@ describe('Deque - Additional Operations', () => {
deque = new Deque<number>();
});
test('addLast should add an element to the end', () => {
deque.addLast(1);
deque.addLast(2);
test('push should add an element to the end', () => {
deque.push(1);
deque.push(2);
expect(deque.last).toBe(2);
expect(deque.size).toBe(2);
});
test('pollLast should remove and return the last element', () => {
deque.addLast(1);
deque.addLast(2);
expect(deque.pollLast()).toBe(2);
test('pop should remove and return the last element', () => {
deque.push(1);
deque.push(2);
expect(deque.pop()).toBe(2);
expect(deque.size).toBe(1);
});
test('addFirst should add an element to the beginning', () => {
deque.addFirst(1);
deque.addFirst(2);
test('unshift should add an element to the beginning', () => {
deque.unshift(1);
deque.unshift(2);
expect(deque.first).toBe(2);
expect(deque.size).toBe(2);
});
test('pollFirst should remove and return the first element', () => {
deque.addFirst(1);
deque.addFirst(2);
expect(deque.pollFirst()).toBe(2);
test('shift should remove and return the first element', () => {
deque.unshift(1);
deque.unshift(2);
expect(deque.shift()).toBe(2);
expect(deque.size).toBe(1);
});
test('clear should reset the deque', () => {
deque.addFirst(1);
deque.unshift(1);
deque.clear();
expect(deque.size).toBe(0);
expect(deque.isEmpty()).toBeTruthy();
});
test('begin should yield elements from the beginning', () => {
deque.addLast(1);
deque.addLast(2);
deque.push(1);
deque.push(2);
const iterator = deque.begin();
expect(iterator.next().value).toBe(1);
expect(iterator.next().value).toBe(2);
});
test('reverseBegin should yield elements in reverse order', () => {
deque.addLast(1);
deque.addLast(2);
deque.push(1);
deque.push(2);
const iterator = deque.reverseBegin();
expect(iterator.next().value).toBe(2);
expect(iterator.next().value).toBe(1);

View file

@ -23,24 +23,24 @@ describe('Queue', () => {
test('shift should remove the first element', () => {
queue.push(1);
queue.enqueue(2);
queue.push(2);
expect(queue.shift()).toBe(1);
expect(queue.size).toBe(1);
});
test('shift should return undefined if queue is empty', () => {
expect(queue.dequeue()).toBeUndefined();
expect(queue.shift()).toBeUndefined();
});
test('peek should return the first element without removing it', () => {
test('first should return the first element without removing it', () => {
queue.push(1);
queue.push(2);
expect(queue.peek()).toBe(1);
expect(queue.first).toBe(1);
expect(queue.size).toBe(2);
});
test('peek should return undefined if queue is empty', () => {
expect(queue.peek()).toBeUndefined();
test('first should return undefined if queue is empty', () => {
expect(queue.first).toBeUndefined();
});
test('size should return the number of elements', () => {
@ -167,12 +167,12 @@ describe('Queue - Additional Methods', () => {
test('peekLast should return the last element without removing it', () => {
queue.push(1);
queue.push(2);
expect(queue.peekLast()).toBe(2);
expect(queue.last).toBe(2);
expect(queue.size).toBe(2);
});
test('peekLast should return undefined if queue is empty', () => {
expect(queue.peekLast()).toBeUndefined();
expect(queue.last).toBeUndefined();
});
test('at should return the element at the specified index', () => {
@ -239,25 +239,25 @@ describe('LinkedListQueue', () => {
queue = new LinkedListQueue<string>();
});
it('should enqueue elements to the end of the queue', () => {
queue.enqueue('A');
queue.enqueue('B');
expect(queue.peek()).toBe('A');
it('should push elements to the end of the queue', () => {
queue.push('A');
queue.push('B');
expect(queue.first).toBe('A');
expect(queue.size).toBe(2);
});
it('should dequeue elements from the front of the queue', () => {
queue.enqueue('A');
queue.enqueue('B');
const dequeued = queue.dequeue();
it('should shift elements from the front of the queue', () => {
queue.push('A');
queue.push('B');
const dequeued = queue.shift();
expect(dequeued).toBe('A');
expect(queue.peek()).toBe('B');
expect(queue.first).toBe('B');
expect(queue.size).toBe(1);
});
it('should peek at the front of the queue', () => {
queue.enqueue('A');
queue.enqueue('B');
expect(queue.peek()).toBe('A');
queue.push('A');
queue.push('B');
expect(queue.first).toBe('A');
});
});