Optimize the insertAfter method of SinglyLinkedList, insertAfter, insertBefore, and delete methods of DoublyLinkedList to directly add an element after a given node's reference without the need for traversal. And conducted performance test.

Modify the insertBefore and delete methods of SinglyLinkedList to align their method APIs with those of DoublyLinkedList.
This commit is contained in:
Revone 2023-08-20 18:52:57 +08:00
parent 938df50847
commit 2c82e31a29
15 changed files with 228 additions and 130 deletions

View file

@ -61,7 +61,7 @@ export class BinaryIndexedTree {
* the sum.
* @returns the sum of the elements in the range specified by the start and end indices.
*/
public getRangeSum(start: number, end: number): number {
getRangeSum(start: number, end: number): number {
if (!(0 <= start && start <= end && end <= this._sumTree.length))
throw 'Index out of bounds';
return this.getPrefixSum(end) - this.getPrefixSum(start);

View file

@ -243,7 +243,7 @@ export class DoublyLinkedList<T> {
* @returns The `insert` method returns a boolean value. It returns `true` if the insertion is successful, and `false`
* if the index is out of bounds.
*/
insert(index: number, val: T): boolean {
insertAt(index: number, val: T): boolean {
if (index < 0 || index > this.length) return false;
if (index === 0) {
this.unshift(val);
@ -286,30 +286,37 @@ export class DoublyLinkedList<T> {
return removedNode!.val;
}
delete(valOrNode: T): boolean;
delete(valOrNode: DoublyLinkedListNode<T>): boolean;
/**
* The `delete` function removes a node with a specific value from a doubly linked list.
* @param {T} val - The `val` parameter represents the value that you want to delete from the linked list.
* @returns The `delete` method returns a boolean value. It returns `true` if the value `val` is found and deleted from
* the linked list, and `false` if the value is not found in the linked list.
* The `delete` function removes a node from a doubly linked list based on either the node itself or its value.
* @param {T | DoublyLinkedListNode<T>} valOrNode - The `valOrNode` parameter can accept either a value of type `T` or
* a `DoublyLinkedListNode<T>` object.
* @returns The `delete` method returns a boolean value. It returns `true` if the value or node was successfully
* deleted from the doubly linked list, and `false` if the value or node was not found in the list.
*/
delete(val: T): boolean {
let current = this.head;
while (current) {
if (current.val === val) {
if (current === this.head) {
this.shift();
} else if (current === this.tail) {
this.pop();
} else {
const prevNode = current.prev;
const nextNode = current.next;
prevNode!.next = nextNode;
nextNode!.prev = prevNode;
this.length--;
}
return true;
delete(valOrNode: T | DoublyLinkedListNode<T>): boolean {
let node: DoublyLinkedListNode<T> | null;
if (valOrNode instanceof DoublyLinkedListNode<T>) {
node = valOrNode;
} else {
node = this.findNode(valOrNode);
}
if (node) {
if (node === this.head) {
this.shift();
} else if (node === this.tail) {
this.pop();
} else {
const prevNode = node.prev;
const nextNode = node.next;
prevNode!.next = nextNode;
nextNode!.prev = prevNode;
this.length--;
}
current = current.next;
return true;
}
return false;
}
@ -494,16 +501,25 @@ export class DoublyLinkedList<T> {
return accumulator;
}
insertAfter(existingValueOrNode: T, newValue: T): boolean;
insertAfter(existingValueOrNode: DoublyLinkedListNode<T>, newValue: T): boolean;
/**
* The function inserts a new value after an existing value in a doubly linked list.
* @param {T} existingValue - The existing value is the value of the node after which we want to insert the new value.
* @param {T} newValue - The `newValue` parameter represents the value of the new node that you want to insert after
* the existing node.
* @returns The method is returning a boolean value. It returns true if the insertion is successful and false if the
* existing value is not found in the linked list.
* The `insertAfter` function inserts a new node with a given value after an existing node in a doubly linked list.
* @param {T | DoublyLinkedListNode<T>} existingValueOrNode - The existing value or node in the doubly linked list
* after which the new value will be inserted. It can be either the value of the existing node or the existing node
* itself.
* @param {T} newValue - The value that you want to insert into the doubly linked list.
* @returns The method returns a boolean value. It returns true if the insertion is successful, and false if the
* existing value or node is not found in the doubly linked list.
*/
insertAfter(existingValue: T, newValue: T): boolean {
const existingNode = this.findNode(existingValue);
insertAfter(existingValueOrNode: T | DoublyLinkedListNode<T>, newValue: T): boolean {
let existingNode;
if (existingValueOrNode instanceof DoublyLinkedListNode<T>) {
existingNode = existingValueOrNode;
} else {
existingNode = this.findNode(existingValueOrNode);
}
if (existingNode) {
const newNode = new DoublyLinkedListNode(newValue);
@ -523,16 +539,26 @@ export class DoublyLinkedList<T> {
return false;
}
insertBefore(existingValueOrNode: T, newValue: T): boolean;
insertBefore(existingValueOrNode: DoublyLinkedListNode<T>, newValue: T): boolean;
/**
* The `insertBefore` function inserts a new value before an existing value in a doubly linked list.
* @param {T} existingValue - The existing value is the value of the node that you want to insert the new value before.
* @param {T} newValue - The `newValue` parameter represents the value of the new node that you want to insert before
* the existing node.
* @returns The method is returning a boolean value. It returns true if the insertion is successful and false if the
* existing value is not found in the linked list.
* The `insertBefore` function inserts a new value before an existing value or node in a doubly linked list.
* @param {T | DoublyLinkedListNode<T>} existingValueOrNode - The existing value or node in the doubly linked list
* before which the new value will be inserted. It can be either the value of the existing node or the existing node
* itself.
* @param {T} newValue - The `newValue` parameter represents the value that you want to insert into the doubly linked
* list.
* @returns The method returns a boolean value. It returns `true` if the insertion is successful, and `false` if the
* insertion fails.
*/
insertBefore(existingValue: T, newValue: T): boolean {
const existingNode = this.findNode(existingValue);
insertBefore(existingValueOrNode: T | DoublyLinkedListNode<T>, newValue: T): boolean {
let existingNode;
if (existingValueOrNode instanceof DoublyLinkedListNode<T>) {
existingNode = existingValueOrNode;
} else {
existingNode = this.findNode(existingValueOrNode);
}
if (existingNode) {
const newNode = new DoublyLinkedListNode(newValue);

View file

@ -1,2 +1,3 @@
export * from './singly-linked-list';
export * from './doubly-linked-list';
export * from './skip-linked-list';

View file

@ -220,17 +220,23 @@ export class SinglyLinkedList<T> {
return removedNode!.val;
}
delete(valueOrNode: T): boolean;
delete(valueOrNode: SinglyLinkedListNode<T>): boolean;
/**
* The `delete` function removes a specified value from a linked list and returns true if the value was found and
* removed, otherwise it returns false.
* @param {T} value - The value parameter represents the value of the node that needs to be deleted from the linked
* list.
* @returns The `delete` method returns a boolean value. It returns `true` if the value was successfully deleted from
* the linked list, and `false` if the value was not found in the linked list.
* The delete function removes a node with a specific value from a singly linked list.
* @param {T | SinglyLinkedListNode<T>} valueOrNode - The `valueOrNode` parameter can accept either a value of type `T`
* or a `SinglyLinkedListNode<T>` object.
* @returns The `delete` method returns a boolean value. It returns `true` if the value or node is found and
* successfully deleted from the linked list, and `false` if the value or node is not found in the linked list.
*/
delete(value: T): boolean {
let current = this.head;
let prev = null;
delete(valueOrNode: T | SinglyLinkedListNode<T>): boolean {
let value: T;
if (valueOrNode instanceof SinglyLinkedListNode<T>) {
value = valueOrNode.val;
} else {
value = valueOrNode;
}
let current = this.head, prev = null;
while (current) {
if (current.val === value) {
@ -256,7 +262,7 @@ export class SinglyLinkedList<T> {
}
/**
* The `insert` function inserts a value at a specified index in a singly linked list.
* The `insertAt` function inserts a value at a specified index in a singly linked list.
* @param {number} index - The index parameter represents the position at which the new value should be inserted in the
* linked list. It is of type number.
* @param {T} val - The `val` parameter represents the value that you want to insert into the linked list at the
@ -264,7 +270,7 @@ export class SinglyLinkedList<T> {
* @returns The `insert` method returns a boolean value. It returns `true` if the insertion is successful, and `false`
* if the index is out of bounds.
*/
insert(index: number, val: T): boolean {
insertAt(index: number, val: T): boolean {
if (index < 0 || index > this.length) return false;
if (index === 0) {
this.unshift(val);
@ -395,20 +401,25 @@ export class SinglyLinkedList<T> {
return null;
}
insertBefore(existingValue: T, newValue: T): boolean
insertBefore(existingValue: SinglyLinkedListNode<T>, newValue: T): boolean
/**
* The `insertBefore` function inserts a new value before an existing value in a singly linked list.
* @param {T} existingValue - The existing value is the value that already exists in the linked list and before which
* we want to insert a new value.
* @param {T | SinglyLinkedListNode<T>} existingValueOrNode - The existing value or node that you want to insert the
* new value before. It can be either the value itself or a node containing the value in the linked list.
* @param {T} newValue - The `newValue` parameter represents the value that you want to insert into the linked list.
* @returns The `insertBefore` function returns a boolean value. It returns `true` if the `newValue` is successfully
* inserted before the first occurrence of `existingValue` in the linked list. It returns `false` if the
* `existingValue` is not found in the linked list.
* @returns The method `insertBefore` returns a boolean value. It returns `true` if the new value was successfully
* inserted before the existing value, and `false` otherwise.
*/
insertBefore(existingValue: T, newValue: T): boolean {
if (!this.head) {
return false;
}
insertBefore(existingValueOrNode: T | SinglyLinkedListNode<T>, newValue: T): boolean {
if (!this.head) return false;
let existingValue: T;
if (existingValueOrNode instanceof SinglyLinkedListNode<T>) {
existingValue = existingValueOrNode.val;
} else {
existingValue = existingValueOrNode;
}
if (this.head.val === existingValue) {
this.unshift(newValue);
return true;
@ -429,16 +440,24 @@ export class SinglyLinkedList<T> {
return false;
}
insertAfter(existingValueOrNode: T, newValue: T): boolean
insertAfter(existingValueOrNode: SinglyLinkedListNode<T>, newValue: T): boolean
/**
* The function inserts a new value after an existing value in a singly linked list.
* @param {T} existingValue - The existing value is the value of the node after which we want to insert the new value.
* @param {T} newValue - The `newValue` parameter represents the value that you want to insert into the linked list
* after the node with the `existingValue`.
* @returns The method is returning a boolean value. It returns true if the insertion is successful and false if the
* existing value is not found in the linked list.
* The `insertAfter` function inserts a new node with a given value after an existing node in a singly linked list.
* @param {T | SinglyLinkedListNode<T>} existingValueOrNode - The existing value or node in the linked list after which
* the new value will be inserted. It can be either the value of the existing node or the existing node itself.
* @param {T} newValue - The value that you want to insert into the linked list after the existing value or node.
* @returns The method returns a boolean value. It returns true if the new value was successfully inserted after the
* existing value or node, and false if the existing value or node was not found in the linked list.
*/
insertAfter(existingValue: T, newValue: T): boolean {
const existingNode = this.findNode(existingValue);
insertAfter(existingValueOrNode: T | SinglyLinkedListNode<T>, newValue: T): boolean {
let existingNode: T | SinglyLinkedListNode<T> | null;
if (existingValueOrNode instanceof SinglyLinkedListNode) {
existingNode = existingValueOrNode;
} else {
existingNode = this.findNode(existingValueOrNode);
}
if (existingNode) {
const newNode = new SinglyLinkedListNode(newValue);

View file

@ -1 +1,2 @@
export {}
export class SkipLinkedList {
}

View file

@ -33,7 +33,7 @@ export class Matrix2D {
* The function returns a 2D array with three empty arrays.
* @returns An empty 2-dimensional array with 3 empty arrays inside.
*/
public static get empty(): number[][] {
static get empty(): number[][] {
return [[], [], []]
}
@ -41,7 +41,7 @@ export class Matrix2D {
* The above function returns a 3x3 identity matrix.
* @returns The method is returning a 2-dimensional array of numbers representing the identity matrix.
*/
public static get identity(): number[][] {
static get identity(): number[][] {
return [
[1, 0, 0],
[0, 1, 0],
@ -53,7 +53,7 @@ export class Matrix2D {
* @returns The getter method is returning the value of the private variable `_matrix`, which is a two-dimensional
* array of numbers.
*/
public get m(): number[][] {
get m(): number[][] {
return this._matrix
}
@ -63,7 +63,7 @@ export class Matrix2D {
* @returns A new instance of the Vector2D class is being returned. The values of the returned vector are taken from
* the first column of the matrix.
*/
public get toVector(): Vector2D {
get toVector(): Vector2D {
return new Vector2D(this._matrix[0][0], this._matrix[1][0])
}
@ -73,7 +73,7 @@ export class Matrix2D {
* @param {Matrix2D} matrix2 - The parameter `matrix2` is a Matrix2D object.
* @returns a new instance of the Matrix2D class, which is created using the result array.
*/
public static add(matrix1: Matrix2D, matrix2: Matrix2D): Matrix2D {
static add(matrix1: Matrix2D, matrix2: Matrix2D): Matrix2D {
const result = Matrix2D.empty
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
@ -90,7 +90,7 @@ export class Matrix2D {
* representing the matrix elements.
* @returns a new instance of the Matrix2D class, which is created using the result array.
*/
public static subtract(matrix1: Matrix2D, matrix2: Matrix2D): Matrix2D {
static subtract(matrix1: Matrix2D, matrix2: Matrix2D): Matrix2D {
const result = Matrix2D.empty
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
@ -106,7 +106,7 @@ export class Matrix2D {
* @param {Matrix2D} matrix2 - The parameter `matrix2` is a 2D matrix of size 3x3.
* @returns a new instance of the Matrix2D class, created using the result array.
*/
public static multiply(matrix1: Matrix2D, matrix2: Matrix2D): Matrix2D {
static multiply(matrix1: Matrix2D, matrix2: Matrix2D): Matrix2D {
const result = Matrix2D.empty
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
@ -126,7 +126,7 @@ export class Matrix2D {
* @param {number} value - The `value` parameter is a number that you want to multiply each element of the `matrix` by.
* @returns a new instance of the Matrix2D class, which is created using the result array.
*/
public static multiplyByValue(matrix: Matrix2D, value: number): Matrix2D {
static multiplyByValue(matrix: Matrix2D, value: number): Matrix2D {
const result = Matrix2D.empty
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
@ -142,7 +142,7 @@ export class Matrix2D {
* @param {Vector2D} vector - The "vector" parameter is a 2D vector, represented by an object of type Vector2D.
* @returns a Vector2D.
*/
public static multiplyByVector(matrix: Matrix2D, vector: Vector2D): Vector2D {
static multiplyByVector(matrix: Matrix2D, vector: Vector2D): Vector2D {
return Matrix2D.multiply(matrix, new Matrix2D(vector)).toVector
}
@ -154,7 +154,7 @@ export class Matrix2D {
* calculate the centerY value, which is the vertical center of the view.
* @returns a Matrix2D object.
*/
public static view(width: number, height: number): Matrix2D {
static view(width: number, height: number): Matrix2D {
const scaleStep = 1 // Scale every vector * scaleStep
const centerX = width / 2
const centerY = height / 2
@ -172,7 +172,7 @@ export class Matrix2D {
* should be scaled.
* @returns the result of multiplying a new instance of Matrix2D by the given factor.
*/
public static scale(factor: number) {
static scale(factor: number) {
return Matrix2D.multiplyByValue(new Matrix2D(), factor)
}
@ -181,7 +181,7 @@ export class Matrix2D {
* @param {number} radians - The "radians" parameter is the angle in radians by which you want to rotate an object.
* @returns The code is returning a new instance of a Matrix2D object.
*/
public static rotate(radians: number) {
static rotate(radians: number) {
const cos = Math.cos(radians)
const sin = Math.sin(radians)
@ -197,7 +197,7 @@ export class Matrix2D {
* and y, and an optional w component.
* @returns The method is returning a new instance of the Matrix2D class.
*/
public static translate(vector: Vector2D): Matrix2D {
static translate(vector: Vector2D): Matrix2D {
return new Matrix2D([
[1, 0, vector.x],
[0, 1, vector.y],

View file

@ -17,7 +17,7 @@ export class Vector2D {
* The function checks if the x and y values of a point are both zero.
* @returns A boolean value indicating whether both the x and y properties of the object are equal to 0.
*/
public get isZero(): boolean {
get isZero(): boolean {
return this.x === 0 && this.y === 0
}
@ -25,7 +25,7 @@ export class Vector2D {
* The above function calculates the length of a vector using the Pythagorean theorem.
* @returns The length of a vector, calculated using the Pythagorean theorem.
*/
public get length(): number {
get length(): number {
return Math.sqrt((this.x * this.x) + (this.y * this.y))
}
@ -33,7 +33,7 @@ export class Vector2D {
* The function calculates the square of the length of a vector.
* @returns The method is returning the sum of the squares of the x and y values.
*/
public get lengthSq(): number {
get lengthSq(): number {
return (this.x * this.x) + (this.y * this.y)
}
@ -42,7 +42,7 @@ export class Vector2D {
* @returns The method is returning a new instance of the Vector2D class with the x and y values rounded to the nearest
* whole number.
*/
public get rounded(): Vector2D {
get rounded(): Vector2D {
return new Vector2D(Math.round(this.x), Math.round(this.y))
}
@ -56,7 +56,7 @@ export class Vector2D {
* @returns The method is returning a new instance of the Vector2D class with the x and y components of the two input
* vectors added together.
*/
public static add(vector1: Vector2D, vector2: Vector2D): Vector2D {
static add(vector1: Vector2D, vector2: Vector2D): Vector2D {
return new Vector2D(vector1.x + vector2.x, vector1.y + vector2.y)
}
@ -71,7 +71,7 @@ export class Vector2D {
* @returns The method is returning a new Vector2D object with the x and y components subtracted from vector1 and
* vector2.
*/
public static subtract(vector1: Vector2D, vector2: Vector2D): Vector2D {
static subtract(vector1: Vector2D, vector2: Vector2D): Vector2D {
return new Vector2D(vector1.x - vector2.x, vector1.y - vector2.y)
}
@ -84,7 +84,7 @@ export class Vector2D {
* of the "vector" parameter.
* @returns A new Vector2D object with the x and y values subtracted by the given value.
*/
public static subtractValue(vector: Vector2D, value: number): Vector2D {
static subtractValue(vector: Vector2D, value: number): Vector2D {
return new Vector2D(vector.x - value, vector.y - value)
}
@ -96,7 +96,7 @@ export class Vector2D {
* of the vector will be multiplied.
* @returns A new Vector2D object with the x and y values multiplied by the given value.
*/
public static multiply(vector: Vector2D, value: number): Vector2D {
static multiply(vector: Vector2D, value: number): Vector2D {
return new Vector2D(vector.x * value, vector.y * value)
}
@ -108,7 +108,7 @@ export class Vector2D {
* vector.
* @returns A new instance of the Vector2D class with the x and y values divided by the given value.
*/
public static divide(vector: Vector2D, value: number): Vector2D {
static divide(vector: Vector2D, value: number): Vector2D {
return new Vector2D(vector.x / value, vector.y / value)
}
@ -119,7 +119,7 @@ export class Vector2D {
* @param {Vector2D} vector2 - The parameter "vector2" is of type Vector2D.
* @returns a boolean value, which indicates whether the two input vectors are equal or not.
*/
public static equals(vector1: Vector2D, vector2: Vector2D): boolean {
static equals(vector1: Vector2D, vector2: Vector2D): boolean {
return vector1.x === vector2.x && vector1.y === vector2.y
}
@ -133,7 +133,7 @@ export class Vector2D {
* roundingFactor, the vectors are considered equal.
* @returns a boolean value.
*/
public static equalsRounded(vector1: Vector2D, vector2: Vector2D, roundingFactor = 12): boolean {
static equalsRounded(vector1: Vector2D, vector2: Vector2D, roundingFactor = 12): boolean {
const vector = Vector2D.abs(Vector2D.subtract(vector1, vector2))
if (vector.x < roundingFactor && vector.y < roundingFactor) {
return true
@ -148,7 +148,7 @@ export class Vector2D {
* @returns the normalized vector if its length is greater than a very small value (epsilon), otherwise it returns the
* original vector.
*/
public static normalize(vector: Vector2D): Vector2D {
static normalize(vector: Vector2D): Vector2D {
const length = vector.length
if (length > 2.220446049250313e-16) { // Epsilon
return Vector2D.divide(vector, length)
@ -165,7 +165,7 @@ export class Vector2D {
* @returns either the original vector or a truncated version of the vector, depending on whether the length of the
* vector is greater than the maximum value specified.
*/
public static truncate(vector: Vector2D, max: number): Vector2D {
static truncate(vector: Vector2D, max: number): Vector2D {
if (vector.length > max) {
return Vector2D.multiply(Vector2D.normalize(vector), max)
}
@ -178,7 +178,7 @@ export class Vector2D {
* @param {Vector2D} vector - The parameter "vector" is of type Vector2D.
* @returns A new Vector2D object is being returned.
*/
public static perp(vector: Vector2D): Vector2D {
static perp(vector: Vector2D): Vector2D {
return new Vector2D(-vector.y, vector.x)
}
@ -188,7 +188,7 @@ export class Vector2D {
* has two properties: "x" and "y", which represent the x and y components of the vector, respectively.
* @returns A new Vector2D object with the negated x and y values of the input vector. Returns the vector that is the reverse of this vector
*/
public static reverse(vector: Vector2D): Vector2D {
static reverse(vector: Vector2D): Vector2D {
return new Vector2D(-vector.x, -vector.y)
}
@ -200,7 +200,7 @@ export class Vector2D {
* @returns The method is returning a new Vector2D object with the absolute values of the x and y components of the
* input vector.
*/
public static abs(vector: Vector2D): Vector2D {
static abs(vector: Vector2D): Vector2D {
return new Vector2D(Math.abs(vector.x), Math.abs(vector.y))
}
@ -211,7 +211,7 @@ export class Vector2D {
* with an x and y component.
* @returns The dot product of the two input vectors.
*/
public static dot(vector1: Vector2D, vector2: Vector2D): number {
static dot(vector1: Vector2D, vector2: Vector2D): number {
return (vector1.x * vector2.x) + (vector1.y * vector2.y)
}
@ -219,7 +219,7 @@ export class Vector2D {
// * Transform vectors based on the current tranformation matrices: translation, rotation and scale
// * @param vectors The vectors to transform
// */
// public static transform(vector: Vector2D, transformation: Matrix2D): Vector2D {
// static transform(vector: Vector2D, transformation: Matrix2D): Vector2D {
// return Matrix2D.multiplyByVector(transformation, vector)
// }
@ -227,7 +227,7 @@ export class Vector2D {
// * Transform vectors based on the current tranformation matrices: translation, rotation and scale
// * @param vectors The vectors to transform
// */
// public static transformList(vectors: Vector2D[], transformation: Matrix2D): Vector2D[] {
// static transformList(vectors: Vector2D[], transformation: Matrix2D): Vector2D[] {
// return vectors.map(vector => Matrix2D.multiplyByVector(transformation, vector))
// }
@ -241,7 +241,7 @@ export class Vector2D {
* the vector in a 2D space.
* @returns The distance between vector1 and vector2.
*/
public static distance(vector1: Vector2D, vector2: Vector2D): number {
static distance(vector1: Vector2D, vector2: Vector2D): number {
const ySeparation = vector2.y - vector1.y
const xSeparation = vector2.x - vector1.x
return Math.sqrt((ySeparation * ySeparation) + (xSeparation * xSeparation))
@ -255,7 +255,7 @@ export class Vector2D {
* properties `x` and `y` which represent the coordinates of the vector.
* @returns the square of the distance between the two input vectors.
*/
public static distanceSq(vector1: Vector2D, vector2: Vector2D): number {
static distanceSq(vector1: Vector2D, vector2: Vector2D): number {
const ySeparation = vector2.y - vector1.y
const xSeparation = vector2.x - vector1.x
return (ySeparation * ySeparation) + (xSeparation * xSeparation)
@ -270,7 +270,7 @@ export class Vector2D {
* vector2. Both vector1 and vector2 are of type Vector2D.
* @returns either -1 or 1. Returns positive if v2 is clockwise of this vector, negative if counterclockwise
*/
public static sign(vector1: Vector2D, vector2: Vector2D): number {
static sign(vector1: Vector2D, vector2: Vector2D): number {
if (vector1.y * vector2.x > vector1.x * vector2.y) {
return -1
}
@ -285,7 +285,7 @@ export class Vector2D {
* respectively.
* @returns the angle between the given vector and the vector (0, -1) in radians.Returns the angle between origin and the given vector in radians
*/
public static angle(vector: Vector2D): number {
static angle(vector: Vector2D): number {
const origin = new Vector2D(0, -1)
const radian = Math.acos(Vector2D.dot(vector, origin) / (vector.length * origin.length))
return Vector2D.sign(vector, origin) === 1 ? ((Math.PI * 2) - radian) : radian
@ -298,7 +298,7 @@ export class Vector2D {
* random vector.
* @returns a new instance of the Vector2D class with random x and y values.
*/
public static random(maxX: number, maxY: number): Vector2D {
static random(maxX: number, maxY: number): Vector2D {
const randX = Math.floor(Math.random() * maxX - (maxX / 2))
const randY = Math.floor(Math.random() * maxY - (maxY / 2))
return new Vector2D(randX, randY)
@ -307,7 +307,7 @@ export class Vector2D {
/**
* The function sets the values of x and y to zero.
*/
public zero(): void {
zero(): void {
this.x = 0
this.y = 0
}

View file

@ -0,0 +1 @@
export * from './magnitude';

View file

@ -0,0 +1,11 @@
const orderReducedBy = 2; // reduction of magnitude's order compared to the baseline magnitude
export const magnitude = {
CONSTANT: Math.floor(Number.MAX_SAFE_INTEGER / Math.pow(10, orderReducedBy)),
LOG_N: Math.pow(10, 9 - orderReducedBy),
LINEAR: Math.pow(10, 6 - orderReducedBy),
N_LOG_N: Math.pow(10, 5 - orderReducedBy),
SQUARED: Math.pow(10, 4 - orderReducedBy),
CUBED: Math.pow(10, 3 - orderReducedBy),
FACTORIAL: 20 - orderReducedBy
}

View file

@ -1,4 +1,5 @@
import {DoublyLinkedList} from '../../../../src';
import {magnitude} from '../constants';
describe('DoublyLinkedList Operation Test', () => {
let list: DoublyLinkedList<number>;
@ -39,19 +40,19 @@ describe('DoublyLinkedList Operation Test', () => {
list.push(3);
// Inserting at the beginning
list.insert(0, 0);
list.insertAt(0, 0);
expect(list.length).toBe(4);
expect(list.getAt(0)).toBe(0);
expect(list.getAt(1)).toBe(1);
// Inserting in the middle
list.insert(2, 1.5);
list.insertAt(2, 1.5);
expect(list.length).toBe(5);
expect(list.getAt(2)).toBe(1.5);
expect(list.getAt(3)).toBe(2);
// Inserting at the end
list.insert(5, 4);
list.insertAt(5, 4);
expect(list.length).toBe(6);
expect(list.getAt(5)).toBe(4);
expect(list.tail!.val).toBe(4);
@ -344,24 +345,21 @@ describe('DoublyLinkedList Operation Test', () => {
describe('DoublyLinkedList Performance Test', () => {
describe('should the push and pop methods adhere to a time complexity of O(n) and executed correctly under large scale data', () => {
const list = new DoublyLinkedList<number>();
const iterations = 10000;
const startPushTime = performance.now();
for (let i = 0; i < iterations; i++) {
for (let i = 0; i < magnitude.LINEAR; i++) {
list.unshift(i);
}
expect(performance.now() - startPushTime).toBeLessThan(iterations * 1000);
expect(performance.now() - startPushTime).toBeLessThan(magnitude.LINEAR * 1000);
const startPopTime = performance.now();
expect(list.length).toBeGreaterThan(0);
for (let i = 0; i < iterations; i++) {
for (let i = 0; i < magnitude.LINEAR; i++) {
list.shift();
}
expect(list.pop()).toBeNull();
expect(list.length).toBe(0);
expect(performance.now() - startPopTime).toBeLessThan(iterations * 1000);
expect(performance.now() - startPopTime).toBeLessThan(magnitude.LINEAR * 1000);
});
});

View file

@ -1,2 +1,4 @@
export * from './singly-linked-list.test';
export * from './doubly-linked-list.test';
export * from './linked-list.test';
export * from './skip-linked-list.test';

View file

@ -0,0 +1,37 @@
import {DoublyLinkedList, DoublyLinkedListNode, SinglyLinkedList, SinglyLinkedListNode} from '../../../../src';
import {magnitude} from '../constants';
describe('LinkedList Performance Test', () => {
it('should DoublyLinkedList insertBefore faster than SinglyLinkedList', () => {
const doublyList = new DoublyLinkedList<number>();
const startPushTime = performance.now();
let midNode: DoublyLinkedListNode | null = null;
const midIndex = Math.floor((magnitude.SQUARED) / 2);
for (let i = 0; i < magnitude.SQUARED; i++) {
doublyList.push(i);
if (i === midIndex) {
midNode = doublyList.findNode(i);
} else if (i > midIndex && midNode) {
doublyList.insertBefore(midNode, i);
}
}
const doublyListPushCost = performance.now() - startPushTime;
const singlyList = new SinglyLinkedList<number>();
let midSinglyNode: SinglyLinkedListNode | null = null;
const startSinglyPushTime = performance.now();
for (let i = 0; i < magnitude.SQUARED; i++) {
singlyList.push(i);
if (i === midIndex) {
midSinglyNode = singlyList.findNode(i);
} else if (i > midIndex && midSinglyNode) {
singlyList.insertBefore(midSinglyNode.val, i);
}
}
const singlyListPushCost = performance.now() - startSinglyPushTime;
expect(doublyListPushCost).toBeLessThan(Math.sqrt(singlyListPushCost) + 1000);
});
});

View file

@ -1,4 +1,5 @@
import {SinglyLinkedList} from '../../../../src';
import {magnitude} from '../constants';
describe('SinglyLinkedList Operation Test', () => {
let list: SinglyLinkedList<number>;
@ -296,9 +297,9 @@ describe('SinglyLinkedList Operation Test', () => {
describe('insert and toArray', () => {
it('should insert elements and return array correctly', () => {
list.insert(0, 1);
list.insert(1, 3);
list.insert(1, 2);
list.insertAt(0, 1);
list.insertAt(1, 3);
list.insertAt(1, 2);
expect(list.toArray()).toEqual([1, 2, 3]);
});
});
@ -381,21 +382,20 @@ describe('SinglyLinkedList Operation Test', () => {
describe('SinglyLinkedList Performance Test', () => {
describe('should the push and pop methods adhere to a time complexity of O(n) and executed correctly under large scale data', () => {
const list = new SinglyLinkedList<number>();
const iterations = 10000; // Adjust the number of iterations as needed
const startPushTime = performance.now();
for (let i = 0; i < iterations; i++) {
for (let i = 0; i < magnitude.LINEAR; i++) {
list.push(i);
}
expect(performance.now() - startPushTime).toBeLessThan(iterations * 1000);
expect(performance.now() - startPushTime).toBeLessThan(magnitude.LINEAR * 1000);
const startPopTime = performance.now();
for (let i = 0; i < iterations; i++) {
for (let i = 0; i < magnitude.LINEAR; i++) {
list.pop();
}
expect(performance.now() - startPopTime).toBeLessThan(iterations * 1000);
expect(performance.now() - startPopTime).toBeLessThan(magnitude.LINEAR * 1000);
});
});

View file

@ -1,11 +1,13 @@
import {SkipLinkedList} from '../../../../src'
describe('SkipLinkedList Operation Test', () => {
it('should xxx', function () {
const xxx = new SkipLinkedList();
});
});
describe('SkipLinkedList Performance Test', () => {
it('should xxx', function () {
const xxx = new SkipLinkedList();
});
});

View file

@ -1,4 +1,5 @@
import {MaxPriorityQueue} from '../../../../src';
import {magnitude} from '../constants';
describe('MaxPriorityQueue Operation Test', () => {
@ -79,9 +80,8 @@ describe('MaxPriorityQueue Operation Test', () => {
describe('MaxPriorityQueue Performance Test', () => {
it('should the poll method adheres to a time complexity of O(log n) and executed correctly under large scale distinct data', () => {
const magnitude = 10000;
const nodes = Array.from(new Set<number>(Array.from(new Array(magnitude), () => Math.floor(Math.random() * magnitude * 100))));
expect(nodes.length).toBeGreaterThan(magnitude / 2);
const nodes = Array.from(new Set<number>(Array.from(new Array(magnitude.LINEAR), () => Math.floor(Math.random() * magnitude.LINEAR * 100))));
expect(nodes.length).toBeGreaterThan(magnitude.LINEAR / 2);
const maxPQ = new MaxPriorityQueue<number>({nodes});
let prev = Number.MAX_SAFE_INTEGER;
@ -93,7 +93,7 @@ describe('MaxPriorityQueue Performance Test', () => {
prev = polled;
}
}
expect(performance.now() - startTime).toBeLessThan(Math.log2(magnitude) * 1000);
expect(performance.now() - startTime).toBeLessThan(Math.log2(magnitude.LINEAR) * 1000);
});
it('should sorted.length to be the same as original data', () => {