mirror of
https://github.com/zrwusa/data-structure-typed.git
synced 2024-11-23 12:54:04 +00:00
perf: The add method of BinaryTree doesn't need to check for existence first, it can detect and add in a single traversal. Feat: Discard the ObjectDeque data structure. test: Increased test coverage for Deque and Queue.
This commit is contained in:
parent
c3b79b70f6
commit
93201bddba
|
@ -231,7 +231,6 @@ export class BinaryTree<K = any, V = any, N extends BinaryTreeNode<K, V, N> = Bi
|
|||
* Space Complexity O(1)
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Time Complexity O(log n) - O(n)
|
||||
* Space Complexity O(1)
|
||||
|
@ -243,50 +242,65 @@ export class BinaryTree<K = any, V = any, N extends BinaryTreeNode<K, V, N> = Bi
|
|||
* @returns The function `add` returns either a node (`N`), `null`, or `undefined`.
|
||||
*/
|
||||
add(keyOrNodeOrEntry: BTNodeExemplar<K, V, N>, value?: V): N | null | undefined {
|
||||
|
||||
let inserted: N | null | undefined;
|
||||
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) {
|
||||
const cur = queue.shift()!;
|
||||
if (newNode && cur.key === newNode.key) {
|
||||
this._replaceNode(cur, newNode);
|
||||
return newNode;
|
||||
}
|
||||
const inserted = this._addTo(newNode, cur);
|
||||
if (inserted !== undefined) return inserted;
|
||||
if (cur.left) queue.push(cur.left);
|
||||
if (cur.right) queue.push(cur.right);
|
||||
}
|
||||
};
|
||||
|
||||
if (this.root) {
|
||||
inserted = _bfs(this.root, newNode);
|
||||
} else {
|
||||
this._setRoot(newNode);
|
||||
if (newNode) {
|
||||
this._size = 1;
|
||||
} else {
|
||||
this._size = 0;
|
||||
}
|
||||
inserted = this.root;
|
||||
// If the tree is empty, directly set the new node as the root node
|
||||
if (!this.root) {
|
||||
this._root = newNode;
|
||||
this._size = 1;
|
||||
return newNode;
|
||||
}
|
||||
return inserted;
|
||||
|
||||
const queue = new Queue<N>([this.root]);
|
||||
let potentialParent: N | undefined; // Record the parent node of the potential insertion location
|
||||
|
||||
while (queue.size > 0) {
|
||||
const cur = queue.shift();
|
||||
|
||||
if (!cur) continue;
|
||||
|
||||
// Check for duplicate keys when newNode is not null
|
||||
if (newNode !== null && cur.key === newNode.key) {
|
||||
this._replaceNode(cur, newNode);
|
||||
return newNode; // If duplicate keys are found, no insertion is performed
|
||||
}
|
||||
|
||||
// Record the first possible insertion location found
|
||||
if (potentialParent === undefined && (cur.left === undefined || cur.right === undefined)) {
|
||||
potentialParent = cur;
|
||||
}
|
||||
|
||||
// Continue traversing the left and right subtrees
|
||||
if (cur.left !== null) {
|
||||
cur.left && queue.push(cur.left);
|
||||
}
|
||||
if (cur.right !== null) {
|
||||
cur.right && queue.push(cur.right);
|
||||
}
|
||||
}
|
||||
|
||||
// At the end of the traversal, if the insertion position is found, insert
|
||||
if (potentialParent) {
|
||||
if (potentialParent.left === undefined) {
|
||||
potentialParent.left = newNode;
|
||||
} else if (potentialParent.right === undefined) {
|
||||
potentialParent.right = newNode;
|
||||
}
|
||||
this._size++;
|
||||
return newNode;
|
||||
}
|
||||
|
||||
return undefined; // If the insertion position cannot be found, return undefined
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Time Complexity: O(k log n) - O(k * n)
|
||||
* Space Complexity: O(1)
|
||||
* Comments: The time complexity for adding a node depends on the depth of the tree. In the best case (when the tree is empty), it's O(1). In the worst case (when the tree is a degenerate tree), it's O(n). The space complexity is constant.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Time Complexity: O(k log n) - O(k * n)
|
||||
* Space Complexity: O(1)
|
||||
|
|
|
@ -849,194 +849,4 @@ export class Deque<E> extends IterableElementBase<E> {
|
|||
|
||||
return { bucketIndex, indexInBucket };
|
||||
}
|
||||
}
|
||||
|
||||
// O(1) time complexity of obtaining the element
|
||||
// O(n) time complexity of adding at the beginning and the end
|
||||
// todo tested slowest one
|
||||
export class ObjectDeque<E = number> {
|
||||
constructor(capacity?: number) {
|
||||
if (capacity !== undefined) this._capacity = capacity;
|
||||
}
|
||||
|
||||
protected _nodes: { [key: number]: E } = {};
|
||||
|
||||
get nodes(): { [p: number]: E } {
|
||||
return this._nodes;
|
||||
}
|
||||
|
||||
protected _capacity = Number.MAX_SAFE_INTEGER;
|
||||
|
||||
get capacity(): number {
|
||||
return this._capacity;
|
||||
}
|
||||
|
||||
protected _first = -1;
|
||||
|
||||
get first(): number {
|
||||
return this._first;
|
||||
}
|
||||
|
||||
protected _last = -1;
|
||||
|
||||
get last(): number {
|
||||
return this._last;
|
||||
}
|
||||
|
||||
protected _size = 0;
|
||||
|
||||
get size(): number {
|
||||
return this._size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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-like data structure.
|
||||
* @param {E} element - The `element` parameter represents the element that you want to add to the beginning of the data
|
||||
* structure.
|
||||
*/
|
||||
addFirst(element: E) {
|
||||
if (this.size === 0) {
|
||||
const mid = Math.floor(this.capacity / 2);
|
||||
this._first = mid;
|
||||
this._last = mid;
|
||||
} else {
|
||||
this._first--;
|
||||
}
|
||||
this.nodes[this.first] = element;
|
||||
this._size++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Time Complexity: O(1)
|
||||
* Space Complexity: O(1)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Time Complexity: O(1)
|
||||
* Space Complexity: O(1)
|
||||
*
|
||||
* The addLast function adds an element to the end of an array-like data structure.
|
||||
* @param {E} element - The `element` parameter represents the element that you want to add to the end of the data structure.
|
||||
*/
|
||||
addLast(element: E) {
|
||||
if (this.size === 0) {
|
||||
const mid = Math.floor(this.capacity / 2);
|
||||
this._first = mid;
|
||||
this._last = mid;
|
||||
} else {
|
||||
this._last++;
|
||||
}
|
||||
this.nodes[this.last] = element;
|
||||
this._size++;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 in a data structure.
|
||||
* @returns The element of the first element in the data structure.
|
||||
*/
|
||||
pollFirst() {
|
||||
if (!this.size) return;
|
||||
const element = this.getFirst();
|
||||
delete this.nodes[this.first];
|
||||
this._first++;
|
||||
this._size--;
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Time Complexity: O(1)
|
||||
* Space Complexity: O(1)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Time Complexity: O(1)
|
||||
* Space Complexity: O(1)
|
||||
*
|
||||
* The `getFirst` function returns the first element in an array-like data structure if it exists.
|
||||
* @returns The element at the first position of the `_nodes` array.
|
||||
*/
|
||||
getFirst() {
|
||||
if (this.size) return this.nodes[this.first];
|
||||
}
|
||||
|
||||
/**
|
||||
* Time Complexity: O(1)
|
||||
* Space Complexity: O(1)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Time Complexity: O(1)
|
||||
* Space Complexity: O(1)
|
||||
*
|
||||
* The `pollLast()` function removes and returns the last element in a data structure.
|
||||
* @returns The element that was removed from the data structure.
|
||||
*/
|
||||
pollLast() {
|
||||
if (!this.size) return;
|
||||
const element = this.getLast();
|
||||
delete this.nodes[this.last];
|
||||
this._last--;
|
||||
this._size--;
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Time Complexity: O(1)
|
||||
* Space Complexity: O(1)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Time Complexity: O(1)
|
||||
* Space Complexity: O(1)
|
||||
*
|
||||
* The `getLast()` function returns the last element in an array-like data structure.
|
||||
* @returns The last element in the array "_nodes" is being returned.
|
||||
*/
|
||||
getLast() {
|
||||
if (this.size) return this.nodes[this.last];
|
||||
}
|
||||
|
||||
/**
|
||||
* Time Complexity: O(1)
|
||||
* Space Complexity: O(1)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Time Complexity: O(1)
|
||||
* Space Complexity: O(1)
|
||||
*
|
||||
* The get function returns the element at the specified index in an array-like data structure.
|
||||
* @param {number} index - The index parameter is a number that represents the position of the element you want to
|
||||
* retrieve from the array.
|
||||
* @returns The element at the specified index in the `_nodes` array is being returned. If there is no element at that
|
||||
* index, `undefined` is returned.
|
||||
*/
|
||||
get(index: number) {
|
||||
return this.nodes[this.first + index] || undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function checks if the size of a data structure is less than or equal to zero.
|
||||
* @returns The method is returning a boolean element indicating whether the size of the object is less than or equal to 0.
|
||||
*/
|
||||
isEmpty() {
|
||||
return this.size <= 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
import { BinaryTree, BinaryTreeNode, FamilyPosition, IterationType } from '../../../../src';
|
||||
import { getRandomIntArray } from '../../../utils';
|
||||
// import {isDebugTest} from '../../../config';
|
||||
import { isDebugTest } from '../../../config';
|
||||
|
||||
// const isDebug = isDebugTest;
|
||||
const isDebug = isDebugTest;
|
||||
|
||||
describe('BinaryTreeNode', () => {
|
||||
it('should create an instance of BinaryTreeNode', () => {
|
||||
|
@ -106,7 +106,7 @@ describe('BinaryTree', () => {
|
|||
it('should delete nodes', () => {
|
||||
expect(tree.getHeight(tree.root, IterationType.ITERATIVE)).toBe(-1);
|
||||
expect(tree.getMinHeight()).toBe(-1);
|
||||
const node = tree.add(1);
|
||||
const node1 = tree.add(1);
|
||||
expect(tree.size).toBe(1);
|
||||
|
||||
const leftChild = new BinaryTreeNode<number>(2);
|
||||
|
@ -127,10 +127,10 @@ describe('BinaryTree', () => {
|
|||
tree.delete(new BinaryTreeNode<number>(200));
|
||||
tree.delete(rightChild);
|
||||
|
||||
if (node) {
|
||||
const result = tree.delete(node);
|
||||
if (node1) {
|
||||
const result = tree.delete(node1);
|
||||
expect(result).toHaveLength(1);
|
||||
expect(tree.size).toBe(3);
|
||||
expect(tree.size).toBe(4);
|
||||
expect(tree.getMinHeight(tree.root, IterationType.RECURSIVE)).toBe(1);
|
||||
}
|
||||
});
|
||||
|
@ -260,6 +260,13 @@ describe('BinaryTree', () => {
|
|||
expect(tree.size).toBe(0);
|
||||
expect(tree.root).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should duplicated nodes just replace the node exists', function () {
|
||||
tree.clear();
|
||||
tree.addMany([-10, -10, -10, 9, 9, 20, null, null, 15, 7, 8, null, 2, null, 6, null, null, 8, 8, 8]);
|
||||
|
||||
expect(tree.bfs(node => node ? node.key : null, undefined, undefined, true)).toEqual([-10, 9, 20, null, null, 15, 7, 8, null, 2, null, 6, null, null])
|
||||
});
|
||||
});
|
||||
|
||||
describe('BinaryTree Morris Traversal', () => {
|
||||
|
|
|
@ -1,402 +1,95 @@
|
|||
import { Deque } from '../../../../src';
|
||||
import { bigO } from '../../../utils';
|
||||
import { isDebugTest } from '../../../config';
|
||||
|
||||
const isDebug = isDebugTest;
|
||||
describe('Deque Tests', () => {
|
||||
// Test cases for the Deque class (DoublyLinkedList-based)
|
||||
describe('Deque (DoublyLinkedList-based)', () => {
|
||||
let deque: Deque<number>;
|
||||
|
||||
beforeEach(() => {
|
||||
deque = new Deque<number>();
|
||||
});
|
||||
|
||||
it('should add elements at the beginning and end', () => {
|
||||
deque.addFirst(1);
|
||||
deque.addLast(2);
|
||||
expect(deque.first).toBe(1);
|
||||
expect(deque.last).toBe(2);
|
||||
});
|
||||
|
||||
it('should delete elements from the beginning and end', () => {
|
||||
deque.addFirst(1);
|
||||
deque.addLast(2);
|
||||
deque.pollFirst();
|
||||
deque.pollLast();
|
||||
expect(deque.isEmpty()).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle edge case when removing from an empty deque', () => {
|
||||
const result = deque.pollFirst();
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should correctly report its size', () => {
|
||||
deque.addFirst(1);
|
||||
deque.addLast(2);
|
||||
expect(deque.size).toBe(2);
|
||||
});
|
||||
|
||||
it('should handle adding and removing elements alternately', () => {
|
||||
deque.addFirst(1);
|
||||
expect(deque.pollFirst()).toBe(1);
|
||||
deque.addLast(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.pollFirst()).toBe(1);
|
||||
deque.addFirst(3);
|
||||
expect(deque.pollLast()).toBe(2);
|
||||
expect(deque.size).toBe(1);
|
||||
});
|
||||
// Add more test cases as needed
|
||||
});
|
||||
|
||||
// // Test cases for the ObjectDeque class
|
||||
// describe('ObjectDeque', () => {
|
||||
// let objectDeque: ObjectDeque<string>;
|
||||
//
|
||||
// beforeEach(() => {
|
||||
// objectDeque = new ObjectDeque<string>();
|
||||
// });
|
||||
//
|
||||
// it('should add elements at the beginning and end', () => {
|
||||
// objectDeque.addFirst('one');
|
||||
// objectDeque.addLast('two');
|
||||
// expect(objectDeque.getFirst()).toBe('one');
|
||||
// expect(objectDeque.getLast()).toBe('two');
|
||||
// });
|
||||
//
|
||||
// it('should delete elements from the beginning and end', () => {
|
||||
// objectDeque.addFirst('one');
|
||||
// objectDeque.addLast('two');
|
||||
// objectDeque.pollFirst();
|
||||
// objectDeque.pollLast();
|
||||
// expect(objectDeque.isEmpty()).toBe(true);
|
||||
// });
|
||||
//
|
||||
// it('should handle edge case when removing from an empty deque', () => {
|
||||
// const result = objectDeque.pollFirst();
|
||||
// expect(result).toBeUndefined();
|
||||
// });
|
||||
//
|
||||
// it('should correctly report its size', () => {
|
||||
// objectDeque.addFirst('one');
|
||||
// objectDeque.addLast('two');
|
||||
// expect(objectDeque.size).toBe(2);
|
||||
// });
|
||||
//
|
||||
// // Add more test cases as needed
|
||||
// });
|
||||
});
|
||||
|
||||
describe('Deque Performance Test', () => {
|
||||
const dataSize = 10000;
|
||||
it('should numeric queue be efficient', function () {
|
||||
const startTime = performance.now();
|
||||
const queue = new Deque<number>();
|
||||
for (let i = 0; i < dataSize; i++) {
|
||||
queue.unshift(i);
|
||||
}
|
||||
for (let i = 0; i < dataSize; i++) {
|
||||
queue.pop();
|
||||
}
|
||||
isDebug && console.log(`Queue Deque Test: ${performance.now() - startTime} ms`);
|
||||
expect(performance.now() - startTime).toBeLessThan(bigO.LINEAR * 100);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Deque', () => {
|
||||
describe('Deque - Basic Operations', () => {
|
||||
let deque: Deque<number>;
|
||||
|
||||
beforeEach(() => {
|
||||
deque = new Deque<number>();
|
||||
deque = new Deque<number>([1, 2]);
|
||||
});
|
||||
|
||||
it('should initialize an empty deque', () => {
|
||||
expect(deque.size).toBe(0);
|
||||
expect(deque.isEmpty()).toBe(true);
|
||||
});
|
||||
|
||||
it('should add elements to the front and back', () => {
|
||||
deque.addFirst(1);
|
||||
deque.addLast(2);
|
||||
|
||||
test('push should add elements to the end', () => {
|
||||
expect(deque.size).toBe(2);
|
||||
expect(deque.first).toBe(1);
|
||||
expect(deque.last).toBe(2);
|
||||
});
|
||||
|
||||
it('should remove elements from the front and back', () => {
|
||||
deque.addFirst(1);
|
||||
deque.addLast(2);
|
||||
|
||||
const firstElement = deque.pollFirst();
|
||||
const lastElement = deque.pollLast();
|
||||
|
||||
expect(deque.size).toBe(0);
|
||||
expect(firstElement).toBe(1);
|
||||
expect(lastElement).toBe(2);
|
||||
test('pop should remove elements from the end', () => {
|
||||
expect(deque.pop()).toBe(2);
|
||||
expect(deque.size).toBe(1);
|
||||
expect(deque.pop()).toBe(1);
|
||||
expect(deque.isEmpty()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should get elements by index', () => {
|
||||
deque.addLast(1);
|
||||
deque.addLast(2);
|
||||
deque.addLast(3);
|
||||
test('unshift should add elements to the beginning', () => {
|
||||
deque.clear();
|
||||
deque.unshift(1);
|
||||
deque.unshift(2);
|
||||
expect(deque.size).toBe(2);
|
||||
expect(deque.first).toBe(2);
|
||||
});
|
||||
|
||||
test('shift should remove elements from the beginning', () => {
|
||||
deque.clear();
|
||||
deque.unshift(1);
|
||||
deque.unshift(2);
|
||||
expect(deque.shift()).toBe(2);
|
||||
expect(deque.size).toBe(1);
|
||||
expect(deque.shift()).toBe(1);
|
||||
expect(deque.isEmpty()).toBeTruthy();
|
||||
});
|
||||
|
||||
test('getAt should retrieve the correct element', () => {
|
||||
expect(deque.getAt(0)).toBe(1);
|
||||
expect(deque.getAt(1)).toBe(2);
|
||||
expect(deque.getAt(2)).toBe(3);
|
||||
});
|
||||
|
||||
it('should return undefined for out-of-bounds index', () => {
|
||||
// expect(deque.getAt(0)).toThrowError('Index out of bounds.');
|
||||
// expect(deque.getAt(1)).toThrow('Index out of bounds');
|
||||
// expect(deque.getAt(-1)).toThrow('Index out of bounds');
|
||||
});
|
||||
|
||||
it('should check if the deque is empty', () => {
|
||||
expect(deque.isEmpty()).toBe(true);
|
||||
|
||||
deque.addLast(1);
|
||||
expect(deque.isEmpty()).toBe(false);
|
||||
|
||||
deque.pollFirst();
|
||||
expect(deque.isEmpty()).toBe(true);
|
||||
test('setAt should set the correct element', () => {
|
||||
deque.setAt(0, 3);
|
||||
expect(deque.getAt(0)).toBe(3);
|
||||
});
|
||||
});
|
||||
|
||||
// describe('ObjectDeque', () => {
|
||||
// let deque: ObjectDeque<number>;
|
||||
//
|
||||
// beforeEach(() => {
|
||||
// deque = new ObjectDeque<number>();
|
||||
// });
|
||||
//
|
||||
// it('should add elements to the front of the deque', () => {
|
||||
// deque.addFirst(1);
|
||||
// deque.addFirst(2);
|
||||
//
|
||||
// expect(deque.size).toBe(2);
|
||||
// expect(deque.getFirst()).toBe(2);
|
||||
// expect(deque.getLast()).toBe(1);
|
||||
// });
|
||||
//
|
||||
// it('should add elements to the end of the deque', () => {
|
||||
// deque.addLast(1);
|
||||
// deque.addLast(2);
|
||||
//
|
||||
// expect(deque.size).toBe(2);
|
||||
// expect(deque.getFirst()).toBe(1);
|
||||
// expect(deque.getLast()).toBe(2);
|
||||
// });
|
||||
//
|
||||
// it('should remove elements from the front of the deque', () => {
|
||||
// deque.addLast(1);
|
||||
// deque.addLast(2);
|
||||
//
|
||||
// const removedElement = deque.pollFirst();
|
||||
//
|
||||
// expect(deque.size).toBe(1);
|
||||
// expect(removedElement).toBe(1);
|
||||
// expect(deque.getFirst()).toBe(2);
|
||||
// });
|
||||
//
|
||||
// it('should remove elements from the end of the deque', () => {
|
||||
// deque.addLast(1);
|
||||
// deque.addLast(2);
|
||||
//
|
||||
// const removedElement = deque.pollFirst();
|
||||
//
|
||||
// expect(deque.size).toBe(1);
|
||||
// expect(removedElement).toBe(1);
|
||||
// expect(deque.getLast()).toBe(2);
|
||||
// });
|
||||
//
|
||||
// it('should return the element at the front of the deque without removing it', () => {
|
||||
// deque.addFirst(1);
|
||||
// deque.addFirst(2);
|
||||
//
|
||||
// expect(deque.getFirst()).toBe(2);
|
||||
// expect(deque.size).toBe(2);
|
||||
// });
|
||||
//
|
||||
// it('should return the element at the end of the deque without removing it', () => {
|
||||
// deque.addLast(1);
|
||||
// deque.addLast(2);
|
||||
//
|
||||
// expect(deque.getLast()).toBe(2);
|
||||
// expect(deque.size).toBe(2);
|
||||
// });
|
||||
//
|
||||
// it('should return the correct size of the deque', () => {
|
||||
// deque.addFirst(1);
|
||||
// deque.addLast(2);
|
||||
// deque.addLast(3);
|
||||
//
|
||||
// expect(deque.size).toBe(3);
|
||||
// });
|
||||
//
|
||||
// it('should check if the deque is empty', () => {
|
||||
// expect(deque.isEmpty()).toBe(true);
|
||||
//
|
||||
// deque.addFirst(1);
|
||||
//
|
||||
// expect(deque.isEmpty()).toBe(false);
|
||||
// });
|
||||
//
|
||||
// it('should set elements at a specific index', () => {
|
||||
// deque.addFirst(1);
|
||||
// deque.addLast(2);
|
||||
// deque.addLast(3);
|
||||
//
|
||||
// expect(deque.getFirst()).toBe(1);
|
||||
// expect(deque.get(1)).toBe(2);
|
||||
// expect(deque.getLast()).toBe(3);
|
||||
// });
|
||||
//
|
||||
// it('should insert elements at a specific index', () => {
|
||||
// deque.addFirst(1);
|
||||
// deque.addLast(2);
|
||||
// deque.addLast(3);
|
||||
//
|
||||
// expect(deque.size).toBe(3);
|
||||
// expect(deque.getFirst()).toBe(1);
|
||||
// expect(deque.get(1)).toBe(2);
|
||||
// expect(deque.get(2)).toBe(3);
|
||||
// expect(deque.getLast()).toBe(3);
|
||||
// });
|
||||
// });
|
||||
|
||||
|
||||
describe('Deque', () => {
|
||||
describe('Deque - Complex Operations', () => {
|
||||
let deque: Deque<number>;
|
||||
|
||||
beforeEach(() => {
|
||||
deque = new Deque<number>();
|
||||
});
|
||||
|
||||
// test('initializes with default capacity', () => {
|
||||
// expect(deque.capacity).toBe(10);
|
||||
// });
|
||||
|
||||
// test('initializes with given capacity', () => {
|
||||
// const customDeque = new Deque(20);
|
||||
// expect(customDeque.capacity).toBe(20);
|
||||
// });
|
||||
|
||||
test('is initially empty', () => {
|
||||
expect(deque.isEmpty()).toBe(true);
|
||||
});
|
||||
|
||||
test('pushes and pops elements', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
expect(deque.pop()).toBe(2);
|
||||
expect(deque.pop()).toBe(1);
|
||||
expect(deque.pop()).toBeUndefined();
|
||||
});
|
||||
|
||||
test('unshifts and shifts elements', () => {
|
||||
deque.unshift(1);
|
||||
deque.unshift(2);
|
||||
expect(deque.shift()).toBe(2);
|
||||
expect(deque.shift()).toBe(1);
|
||||
expect(deque.shift()).toBeUndefined();
|
||||
});
|
||||
|
||||
test('correctly reports size', () => {
|
||||
expect(deque.size).toBe(0);
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
expect(deque.size).toBe(2);
|
||||
});
|
||||
|
||||
test('gets first and last elements', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.push(3);
|
||||
expect(deque.first).toBe(1);
|
||||
expect(deque.last).toBe(3);
|
||||
});
|
||||
|
||||
test('handles resizing automatically', () => {
|
||||
for (let i = 0; i < 12; i++) {
|
||||
deque.push(i);
|
||||
}
|
||||
expect(deque.size).toBe(12);
|
||||
// expect(deque.capacity).toBeGreaterThan(10);
|
||||
});
|
||||
|
||||
test('converts to array', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.push(3);
|
||||
expect(deque.toArray()).toEqual([1, 2, 3]);
|
||||
});
|
||||
|
||||
test('clears the deque', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.clear();
|
||||
expect(deque.isEmpty()).toBe(true);
|
||||
});
|
||||
|
||||
test('inserts and deletes at specific index', () => {
|
||||
test('insertAt should insert elements at the specified position', () => {
|
||||
deque.push(1);
|
||||
deque.push(3);
|
||||
deque.insertAt(1, 2);
|
||||
expect(deque.toArray()).toEqual([1, 2, 3]);
|
||||
expect(deque.deleteAt(1)).toBe(2);
|
||||
});
|
||||
|
||||
test('cut should remove elements after the specified position', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.push(3);
|
||||
deque.cut(1);
|
||||
expect(deque.toArray()).toEqual([1, 2]);
|
||||
});
|
||||
|
||||
test('deleteAt should remove the element at the specified position', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.push(3);
|
||||
deque.deleteAt(1);
|
||||
expect(deque.toArray()).toEqual([1, 3]);
|
||||
});
|
||||
|
||||
test('finds elements with a callback', () => {
|
||||
test('delete should remove all instances of an element', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.push(2);
|
||||
deque.push(3);
|
||||
expect(deque.find(el => el > 1)).toBe(2);
|
||||
deque.delete(2);
|
||||
expect(deque.toArray()).toEqual([1, 3]);
|
||||
});
|
||||
|
||||
test('performs forEach operation', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
let sum = 0;
|
||||
deque.forEach(el => {
|
||||
sum += el;
|
||||
});
|
||||
expect(sum).toBe(3);
|
||||
});
|
||||
|
||||
test('maps to a new deque', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
const newDeque = deque.map(el => el * el);
|
||||
expect(newDeque.toArray()).toEqual([1, 4]);
|
||||
});
|
||||
|
||||
test('filters elements', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.push(3);
|
||||
const newDeque = deque.filter(el => el % 2 === 0);
|
||||
expect(newDeque.toArray()).toEqual([2]);
|
||||
});
|
||||
|
||||
test('reduces elements', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.push(3);
|
||||
const sum = deque.reduce((acc, el) => acc + el, 0);
|
||||
expect(sum).toBe(6);
|
||||
});
|
||||
|
||||
test('reverses elements', () => {
|
||||
test('reverse should reverse the order of elements', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.push(3);
|
||||
|
@ -404,72 +97,277 @@ describe('Deque', () => {
|
|||
expect(deque.toArray()).toEqual([3, 2, 1]);
|
||||
});
|
||||
|
||||
test('gets element at a specific index', () => {
|
||||
test('unique should remove duplicate elements', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.push(3);
|
||||
expect(deque.getAt(1)).toBe(2);
|
||||
// expect(deque.getAt(5)).toThrow();
|
||||
});
|
||||
|
||||
test('finds the index of an element', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.push(3);
|
||||
expect(deque.indexOf(2)).toBe(1);
|
||||
expect(deque.indexOf(4)).toBe(-1);
|
||||
deque.unique();
|
||||
expect(deque.toArray()).toEqual([1, 2, 3]);
|
||||
});
|
||||
|
||||
|
||||
//Test begin method
|
||||
describe('begin()', () => {
|
||||
it('should return an iterator at the beginning of the deque', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.push(3);
|
||||
|
||||
const iterator = deque.begin();
|
||||
|
||||
expect(iterator.next().value).toBe(1);
|
||||
});
|
||||
test('sort should sort elements according to a comparator', () => {
|
||||
deque.push(3);
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.sort((a, b) => a - b);
|
||||
expect(deque.toArray()).toEqual([1, 2, 3]);
|
||||
});
|
||||
|
||||
// Test the reverse Begin method
|
||||
describe('reverseBegin()', () => {
|
||||
it('should return a reverse iterator at the beginning of the deque', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.push(3);
|
||||
|
||||
const iterator = deque.reverseBegin();
|
||||
|
||||
expect(iterator.next().value).toBe(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('iterable methods', () => {
|
||||
it('should forEach, some, every, filter, map, reduce of the deque', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.push(3);
|
||||
|
||||
const mockCallback = jest.fn();
|
||||
deque.forEach((element) => {
|
||||
mockCallback(element);
|
||||
});
|
||||
|
||||
expect(mockCallback.mock.calls.length).toBe(3);
|
||||
expect(mockCallback.mock.calls[0]).toEqual([1]);
|
||||
expect(mockCallback.mock.calls[1]).toEqual([2]);
|
||||
expect(mockCallback.mock.calls[2]).toEqual([3]);
|
||||
|
||||
expect(deque.every(element => element > 0)).toBe(true);
|
||||
expect(deque.every(element => element > 1)).toBe(false);
|
||||
expect(deque.some(element => element > 2)).toBe(true);
|
||||
|
||||
expect([...deque.filter(element => element > 2)]).toEqual([3]);
|
||||
expect([...deque.map(element => element * 2)]).toEqual([2, 4, 6]);
|
||||
expect(deque.reduce((accumulator, element) => accumulator + element, 0)).toEqual(6);
|
||||
});
|
||||
test('shrinkToFit should reduce the memory footprint', () => {
|
||||
});
|
||||
});
|
||||
describe('Deque - Utility Operations', () => {
|
||||
let deque: Deque<number>;
|
||||
|
||||
beforeEach(() => {
|
||||
deque = new Deque<number>();
|
||||
});
|
||||
|
||||
test('find should return the first element that matches the condition', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.push(3);
|
||||
const found = deque.find(element => element > 1);
|
||||
expect(found).toBe(2);
|
||||
});
|
||||
|
||||
test('indexOf should return the index of the first occurrence of an element', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.push(3);
|
||||
const index = deque.indexOf(2);
|
||||
expect(index).toBe(1);
|
||||
});
|
||||
|
||||
test('toArray should convert the deque to an array', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.push(3);
|
||||
expect(deque.toArray()).toEqual([1, 2, 3]);
|
||||
});
|
||||
|
||||
test('filter should filter elements based on a predicate', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.push(3);
|
||||
const filtered = deque.filter(element => element > 1);
|
||||
expect(filtered.toArray()).toEqual([2, 3]);
|
||||
});
|
||||
|
||||
test('map should apply a function to all elements', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.push(3);
|
||||
const mapped = deque.map(element => element * 2);
|
||||
expect(mapped.toArray()).toEqual([2, 4, 6]);
|
||||
});
|
||||
|
||||
test('print should print the deque elements', () => {
|
||||
const consoleSpy = jest.spyOn(console, 'log');
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
deque.print();
|
||||
expect(consoleSpy).toHaveBeenCalledWith([1, 2]);
|
||||
});
|
||||
|
||||
});
|
||||
describe('Deque - Additional Operations', () => {
|
||||
let deque: Deque<number>;
|
||||
|
||||
beforeEach(() => {
|
||||
deque = new Deque<number>();
|
||||
});
|
||||
|
||||
test('addLast should add an element to the end', () => {
|
||||
deque.addLast(1);
|
||||
deque.addLast(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);
|
||||
expect(deque.size).toBe(1);
|
||||
});
|
||||
|
||||
test('addFirst should add an element to the beginning', () => {
|
||||
deque.addFirst(1);
|
||||
deque.addFirst(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);
|
||||
expect(deque.size).toBe(1);
|
||||
});
|
||||
|
||||
test('clear should reset the deque', () => {
|
||||
deque.addFirst(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);
|
||||
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);
|
||||
const iterator = deque.reverseBegin();
|
||||
expect(iterator.next().value).toBe(2);
|
||||
expect(iterator.next().value).toBe(1);
|
||||
});
|
||||
|
||||
});
|
||||
describe('Deque - push Method', () => {
|
||||
let deque: Deque<number>;
|
||||
const bucketSize = 10; // 假设的 bucket 大小
|
||||
|
||||
beforeEach(() => {
|
||||
deque = new Deque<number>([], bucketSize);
|
||||
});
|
||||
|
||||
test('push should add an element when deque is empty', () => {
|
||||
deque.push(1);
|
||||
expect(deque.last).toBe(1);
|
||||
expect(deque.size).toBe(1);
|
||||
});
|
||||
|
||||
test('push should add an element when lastInBucket is not at max', () => {
|
||||
for (let i = 0; i < bucketSize - 1; i++) {
|
||||
deque.push(i);
|
||||
}
|
||||
deque.push(bucketSize);
|
||||
expect(deque.last).toBe(bucketSize);
|
||||
expect(deque.size).toBe(bucketSize);
|
||||
});
|
||||
|
||||
test('push should add an element and move to next bucket when last bucket is full', () => {
|
||||
for (let i = 0; i < bucketSize; i++) {
|
||||
deque.push(i);
|
||||
}
|
||||
deque.push(bucketSize + 1);
|
||||
expect(deque.last).toBe(bucketSize + 1);
|
||||
expect(deque.size).toBe(bucketSize + 1);
|
||||
});
|
||||
|
||||
test('push should add an element and reallocate when last bucket and lastInBucket are at max', () => {
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
deque.push(i);
|
||||
}
|
||||
|
||||
deque.push(100);
|
||||
expect(deque.last).toBe(100);
|
||||
expect(deque.size).toBeGreaterThan(bucketSize);
|
||||
});
|
||||
});
|
||||
describe('Deque - pop Method', () => {
|
||||
let deque: Deque<number>;
|
||||
const bucketSize = 10;
|
||||
|
||||
beforeEach(() => {
|
||||
deque = new Deque<number>([], bucketSize);
|
||||
});
|
||||
|
||||
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('pop should handle popping the only element', () => {
|
||||
deque.push(1);
|
||||
expect(deque.pop()).toBe(1);
|
||||
expect(deque.isEmpty()).toBeTruthy();
|
||||
});
|
||||
|
||||
test('pop should adjust bucketLast and lastInBucket correctly', () => {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
deque.push(i);
|
||||
}
|
||||
for (let i = 0; i < 1001; i++) {
|
||||
const lastElement = deque.last;
|
||||
expect(deque.pop()).toBe(lastElement);
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
describe('Deque - unshift Method', () => {
|
||||
let deque: Deque<number>;
|
||||
const bucketSize = 10;
|
||||
|
||||
beforeEach(() => {
|
||||
deque = new Deque<number>([], bucketSize);
|
||||
});
|
||||
|
||||
test('unshift should add an element to the beginning when deque is empty', () => {
|
||||
deque.unshift(1);
|
||||
expect(deque.first).toBe(1);
|
||||
expect(deque.size).toBe(1);
|
||||
});
|
||||
|
||||
test('unshift should add an element to the beginning and adjust firstInBucket', () => {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
deque.unshift(i);
|
||||
}
|
||||
|
||||
deque.unshift(0);
|
||||
expect(deque.first).toBe(0);
|
||||
});
|
||||
|
||||
test('unshift should add an element and reallocate when needed', () => {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
deque.unshift(i);
|
||||
}
|
||||
deque.unshift(-1);
|
||||
expect(deque.first).toBe(-1);
|
||||
});
|
||||
});
|
||||
describe('Deque - shift Method', () => {
|
||||
let deque: Deque<number>;
|
||||
|
||||
const bucketSize = 10;
|
||||
|
||||
beforeEach(() => {
|
||||
deque = new Deque<number>([], bucketSize);
|
||||
});
|
||||
|
||||
test('shift should remove and return the first element', () => {
|
||||
deque.push(1);
|
||||
deque.push(2);
|
||||
expect(deque.shift()).toBe(1);
|
||||
expect(deque.size).toBe(1);
|
||||
});
|
||||
|
||||
test('shift should handle shifting the only element', () => {
|
||||
deque.push(1);
|
||||
expect(deque.shift()).toBe(1);
|
||||
expect(deque.isEmpty()).toBeTruthy();
|
||||
});
|
||||
|
||||
test('shift should adjust bucketFirst and firstInBucket correctly', () => {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
deque.push(i);
|
||||
}
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const firstElement = deque.first;
|
||||
expect(deque.shift()).toBe(firstElement);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,21 +1,7 @@
|
|||
import { LinkedListQueue, Queue } from '../../../../src';
|
||||
import { bigO } from '../../../utils';
|
||||
import { isDebugTest } from '../../../config';
|
||||
|
||||
const isDebug = isDebugTest;
|
||||
describe('Queue Operation Test', () => {
|
||||
it('should validate a queue', () => {
|
||||
const queue = new Queue<number>();
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
queue.enqueue(i);
|
||||
}
|
||||
let last: number | undefined = 0;
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
last = queue.dequeue();
|
||||
}
|
||||
expect(last).toBe(999);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Queue', () => {
|
||||
let queue: Queue<number>;
|
||||
|
@ -24,117 +10,209 @@ describe('Queue', () => {
|
|||
queue = new Queue<number>();
|
||||
});
|
||||
|
||||
it('should initialize an empty queue', () => {
|
||||
test('new Queue() should create an empty queue', () => {
|
||||
expect(queue.size).toBe(0);
|
||||
expect(queue.isEmpty()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should push elements to the end of the queue', () => {
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
expect(queue.peek()).toBe(1);
|
||||
expect(queue.size).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Queue', () => {
|
||||
let queue: Queue<number>;
|
||||
|
||||
beforeEach(() => {
|
||||
queue = new Queue<number>();
|
||||
});
|
||||
|
||||
it('should initialize an empty queue', () => {
|
||||
expect(queue.size).toBe(0);
|
||||
expect(queue.isEmpty()).toBe(true);
|
||||
});
|
||||
|
||||
it('should push elements to the end of the queue', () => {
|
||||
test('push should add elements to the queue', () => {
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
expect(queue.size).toBe(2);
|
||||
expect(queue.peek()).toBe(1);
|
||||
expect(queue.getLast()).toBe(2);
|
||||
});
|
||||
|
||||
it('should shift elements from the front of the queue', () => {
|
||||
test('shift should remove the first element', () => {
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
const shifted = queue.shift();
|
||||
expect(shifted).toBe(1);
|
||||
queue.enqueue(2);
|
||||
expect(queue.shift()).toBe(1);
|
||||
expect(queue.size).toBe(1);
|
||||
expect(queue.peek()).toBe(2);
|
||||
expect(queue.getLast()).toBe(2);
|
||||
});
|
||||
|
||||
it('should handle shifting when queue reaches half size', () => {
|
||||
for (let i = 1; i <= 5; i++) {
|
||||
queue.push(i);
|
||||
}
|
||||
for (let i = 1; i <= 3; i++) {
|
||||
queue.shift();
|
||||
}
|
||||
// Queue size should be 2, but internal array size is still 5.
|
||||
// Test that shifting optimizes the internal array.
|
||||
expect(queue.size).toBe(2);
|
||||
expect(queue.nodes.length).toBe(2);
|
||||
expect(queue.peek()).toBe(4);
|
||||
test('shift should return undefined if queue is empty', () => {
|
||||
expect(queue.dequeue()).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should peek at the front and end of the queue', () => {
|
||||
test('peek should return the first element without removing it', () => {
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
expect(queue.peek()).toBe(1);
|
||||
expect(queue.getLast()).toBe(2);
|
||||
expect(queue.size).toBe(2);
|
||||
});
|
||||
|
||||
it('should handle shifting when the queue is empty', () => {
|
||||
const shifted = queue.shift();
|
||||
expect(shifted).toBeUndefined();
|
||||
expect(queue.size).toBe(0);
|
||||
test('peek should return undefined if queue is empty', () => {
|
||||
expect(queue.peek()).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle peeking when the queue is empty', () => {
|
||||
expect(queue.peek()).toBeUndefined();
|
||||
expect(queue.getLast()).toBeUndefined();
|
||||
test('size should return the number of elements', () => {
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
expect(queue.size).toBe(2);
|
||||
});
|
||||
|
||||
it('should handle clearing the queue', () => {
|
||||
for (let i = 1; i <= 3; i++) {
|
||||
queue.push(i);
|
||||
}
|
||||
test('isEmpty should return true if the queue is empty', () => {
|
||||
expect(queue.isEmpty()).toBeTruthy();
|
||||
});
|
||||
|
||||
test('isEmpty should return false if the queue is not empty', () => {
|
||||
queue.push(1);
|
||||
expect(queue.isEmpty()).toBeFalsy();
|
||||
});
|
||||
|
||||
test('toArray should return an array of queue elements', () => {
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
expect(queue.toArray()).toEqual([1, 2]);
|
||||
});
|
||||
|
||||
test('clear should remove all elements from the queue', () => {
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.clear();
|
||||
expect(queue.size).toBe(0);
|
||||
expect(queue.peek()).toBeUndefined();
|
||||
expect(queue.getLast()).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should clone the queue', () => {
|
||||
for (let i = 1; i <= 3; i++) {
|
||||
test('forEach should iterate over all elements', () => {
|
||||
const arr: number[] = [];
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.forEach(element => arr.push(element));
|
||||
expect(arr).toEqual([1, 2]);
|
||||
});
|
||||
|
||||
// Boundary value testing
|
||||
test('push and shift with many elements', () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
queue.push(i);
|
||||
}
|
||||
const clonedQueue = queue.clone();
|
||||
expect(clonedQueue.size).toBe(3);
|
||||
expect(clonedQueue.peek()).toBe(1);
|
||||
expect(clonedQueue.getLast()).toBe(3);
|
||||
});
|
||||
|
||||
it('should handle creating a queue from an array', () => {
|
||||
const elements = [1, 2, 3, 4, 5];
|
||||
const newQueue = Queue.fromArray(elements);
|
||||
expect(newQueue.size).toBe(5);
|
||||
expect(newQueue.peek()).toBe(1);
|
||||
expect(newQueue.getLast()).toBe(5);
|
||||
});
|
||||
|
||||
it('should iterate through the queue', () => {
|
||||
for (let i = 1; i <= 3; i++) {
|
||||
queue.push(i);
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
expect(queue.shift()).toBe(i);
|
||||
}
|
||||
const values = Array.from(queue);
|
||||
expect(values).toEqual([1, 2, 3]);
|
||||
expect(queue.isEmpty()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Queue - Advanced Methods', () => {
|
||||
let queue: Queue<number>;
|
||||
|
||||
beforeEach(() => {
|
||||
queue = new Queue<number>();
|
||||
});
|
||||
|
||||
test('reduce should apply a function against an accumulator and each element', () => {
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.push(3);
|
||||
const sum = queue.reduce((acc, val) => acc + val, 0);
|
||||
expect(sum).toBe(6);
|
||||
});
|
||||
|
||||
test('reduce should return initial value for empty queue', () => {
|
||||
const initialValue = 0;
|
||||
const sum = queue.reduce((acc, val) => acc + val, initialValue);
|
||||
expect(sum).toBe(initialValue);
|
||||
});
|
||||
|
||||
test('filter should return a new queue with all elements that pass the test implemented by provided function', () => {
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.push(3);
|
||||
const filteredQueue = queue.filter(val => val > 1);
|
||||
expect(filteredQueue.toArray()).toEqual([2, 3]);
|
||||
});
|
||||
|
||||
test('filter should return an empty queue for empty queue', () => {
|
||||
const filteredQueue = queue.filter(val => val > 1);
|
||||
expect(filteredQueue.isEmpty()).toBeTruthy();
|
||||
});
|
||||
|
||||
test('map should create a new queue with the results of calling a provided function on every element', () => {
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.push(3);
|
||||
const mappedQueue = queue.map(val => val * 2);
|
||||
expect(mappedQueue.toArray()).toEqual([2, 4, 6]);
|
||||
});
|
||||
|
||||
test('map should return an empty queue for empty queue', () => {
|
||||
const mappedQueue = queue.map(val => val * 2);
|
||||
expect(mappedQueue.isEmpty()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
describe('Queue - Additional Methods', () => {
|
||||
let queue: Queue<number>;
|
||||
|
||||
beforeEach(() => {
|
||||
queue = new Queue<number>();
|
||||
});
|
||||
|
||||
test('peekLast should return the last element without removing it', () => {
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
expect(queue.peekLast()).toBe(2);
|
||||
expect(queue.size).toBe(2);
|
||||
});
|
||||
|
||||
test('peekLast should return undefined if queue is empty', () => {
|
||||
expect(queue.peekLast()).toBeUndefined();
|
||||
});
|
||||
|
||||
test('getAt should return the element at the specified index', () => {
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.push(3);
|
||||
expect(queue.getAt(1)).toBe(2);
|
||||
});
|
||||
|
||||
test('getAt should return undefined for an invalid index', () => {
|
||||
queue.push(1);
|
||||
expect(queue.getAt(3)).toBeUndefined();
|
||||
expect(queue.getAt(-1)).toBeUndefined();
|
||||
});
|
||||
|
||||
test('print should not throw any errors', () => {
|
||||
expect(() => {
|
||||
queue.push(1);
|
||||
queue.print();
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Queue - Static and Clone Methods', () => {
|
||||
test('fromArray should create a new queue from an array', () => {
|
||||
const array = [1, 2, 3];
|
||||
const queue = Queue.fromArray(array);
|
||||
expect(queue.toArray()).toEqual(array);
|
||||
expect(queue.size).toBe(array.length);
|
||||
});
|
||||
|
||||
test('fromArray should create an empty queue from an empty array', () => {
|
||||
const queue = Queue.fromArray([]);
|
||||
expect(queue.isEmpty()).toBeTruthy();
|
||||
});
|
||||
|
||||
test('clone should create a new queue with the same elements', () => {
|
||||
const originalQueue = new Queue<number>();
|
||||
originalQueue.push(1);
|
||||
originalQueue.push(2);
|
||||
|
||||
const clonedQueue = originalQueue.clone();
|
||||
expect(clonedQueue.toArray()).toEqual(originalQueue.toArray());
|
||||
expect(clonedQueue.size).toBe(originalQueue.size);
|
||||
});
|
||||
|
||||
test('clone should not affect the original queue when mutated', () => {
|
||||
const originalQueue = new Queue<number>();
|
||||
originalQueue.push(1);
|
||||
originalQueue.push(2);
|
||||
|
||||
const clonedQueue = originalQueue.clone();
|
||||
clonedQueue.push(3);
|
||||
|
||||
expect(clonedQueue.size).not.toBe(originalQueue.size);
|
||||
expect(originalQueue.toArray()).not.toContain(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('LinkedListQueue', () => {
|
||||
let queue: LinkedListQueue<string>;
|
||||
|
||||
|
@ -163,82 +241,4 @@ describe('LinkedListQueue', () => {
|
|||
queue.enqueue('B');
|
||||
expect(queue.peek()).toBe('A');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Queue Performance Test', () => {
|
||||
const dataSize = 10000;
|
||||
it('should numeric queue be efficient', function () {
|
||||
const startTime = performance.now();
|
||||
const queue = new Queue<number>();
|
||||
for (let i = 0; i < dataSize; i++) {
|
||||
queue.enqueue(i);
|
||||
}
|
||||
for (let i = 0; i < dataSize; i++) {
|
||||
queue.dequeue();
|
||||
}
|
||||
isDebug && console.log(`Queue Performance Test: ${performance.now() - startTime} ms`);
|
||||
expect(performance.now() - startTime).toBeLessThan(bigO.LINEAR * 100);
|
||||
});
|
||||
|
||||
it('should numeric Array be more efficient than Queue when the data size is 10000', function () {
|
||||
const startTime2 = performance.now();
|
||||
const queue2: number[] = [];
|
||||
for (let i = 0; i < dataSize; i++) {
|
||||
queue2.push(i);
|
||||
}
|
||||
for (let i = 0; i < dataSize; i++) {
|
||||
queue2.shift();
|
||||
}
|
||||
expect(performance.now() - startTime2).toBeLessThan(bigO.CUBED * 100);
|
||||
});
|
||||
|
||||
it('should numeric LinkedListQueue be efficient', function () {
|
||||
const startTime = performance.now();
|
||||
const queue = new LinkedListQueue<number>();
|
||||
for (let i = 0; i < dataSize; i++) {
|
||||
queue.enqueue(i);
|
||||
}
|
||||
for (let i = 0; i < dataSize; i++) {
|
||||
queue.dequeue();
|
||||
}
|
||||
// console.log(`LinkedListQueue Performance Test: ${performance.now() - startTime} ms`);
|
||||
expect(performance.now() - startTime).toBeLessThan(bigO.LINEAR * 100);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('Queue iterative methods', () => {
|
||||
let queue: Queue<number>;
|
||||
|
||||
beforeEach(() => {
|
||||
queue = new Queue();
|
||||
for (let i = 0; i < 10; i++) {
|
||||
queue.enqueue(i);
|
||||
}
|
||||
});
|
||||
|
||||
test('iterator should provide access to all elements', () => {
|
||||
const elements = [];
|
||||
for (const item of queue) {
|
||||
elements.push(item);
|
||||
}
|
||||
expect(elements).toEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||
});
|
||||
|
||||
test('forEach should apply the callback to each element', () => {
|
||||
const elements: number[] = [];
|
||||
queue.forEach((element) => elements.push(element * 2));
|
||||
expect(elements).toEqual([0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
|
||||
});
|
||||
|
||||
test('filter should return a new queue with only the elements that satisfy the predicate', () => {
|
||||
const filteredQueue = queue.filter(element => element % 2 === 0);
|
||||
expect([...filteredQueue]).toEqual([0, 2, 4, 6, 8]);
|
||||
});
|
||||
|
||||
test('map should return a new queue with the transformed elements', () => {
|
||||
const mappedQueue = queue.map(element => element * 2);
|
||||
expect([...mappedQueue]).toEqual([0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in a new issue