diff --git a/DIRECTORY.md b/DIRECTORY.md index 185bae95..83faf590 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -71,6 +71,10 @@ * Tries * [Tries.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/tries/test/tries.test.ts) * [Tries](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/tries/tries.ts) + * Vectors + * Test + * [Vector2.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/vectors/test/vector2.test.ts) + * [Vector2](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/vectors/vector2.ts) ## Dynamic Programming * [Coin Change](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/dynamic_programming/coin_change.ts) @@ -156,6 +160,8 @@ ## Search * [Binary Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/binary_search.ts) + * [Exponential Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/exponential_search.ts) + * [Fibonacci Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/fibonacci_search.ts) * [Interpolation Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/interpolation_search.ts) * [Jump Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/jump_search.ts) * [Linear Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/linear_search.ts) diff --git a/data_structures/vectors/test/vector2.test.ts b/data_structures/vectors/test/vector2.test.ts new file mode 100644 index 00000000..fa146c3b --- /dev/null +++ b/data_structures/vectors/test/vector2.test.ts @@ -0,0 +1,150 @@ +import { Vector2 } from '../vector2' + +describe('Vector2', () => { + describe('#equalsExactly', () => { + it('should compare equality correctly', () => { + expect(new Vector2(1, 0).equalsExactly(new Vector2(1, 0))).toBe(true) + + expect(new Vector2(1.23, 4.56).equalsExactly(new Vector2(0, 0))).toBe( + false + ) + }) + }) + + describe('#equalsApproximately', () => { + it('should compare equality (approximately) correctly', () => { + expect( + new Vector2(1, 0).equalsApproximately( + new Vector2(1, 0.0000001), + 0.000001 + ) + ).toBe(true) + + expect( + new Vector2(1.23, 4.56).equalsApproximately( + new Vector2(1.24, 4.56), + 0.000001 + ) + ).toBe(false) + }) + }) + + describe('#add', () => { + it('should add two vectors correctly', () => { + expect( + new Vector2(1, 0) + .add(new Vector2(0, 1)) + .equalsApproximately(new Vector2(1, 1), 0.000001) + ).toBe(true) + + expect( + new Vector2(-3.3, -9) + .add(new Vector2(-2.2, 3)) + .equalsApproximately(new Vector2(-5.5, -6), 0.000001) + ).toBe(true) + }) + }) + + describe('#subtract', () => { + it('should subtract two vectors correctly', () => { + expect( + new Vector2(1, 0) + .subtract(new Vector2(0, 1)) + .equalsApproximately(new Vector2(1, -1), 0.000001) + ).toBe(true) + + expect( + new Vector2(234.5, 1.7) + .subtract(new Vector2(3.3, 2.7)) + .equalsApproximately(new Vector2(231.2, -1), 0.000001) + ).toBe(true) + }) + }) + + describe('#multiply', () => { + it('should multiply two vectors correctly', () => { + expect( + new Vector2(1, 0) + .multiply(5) + .equalsApproximately(new Vector2(5, 0), 0.000001) + ).toBe(true) + + expect( + new Vector2(3.41, -7.12) + .multiply(-3.1) + .equalsApproximately(new Vector2(-10.571, 22.072), 0.000001) + ).toBe(true) + }) + }) + + describe('#length', () => { + it('should calculate its length correctly', () => { + expect(new Vector2(1, 0).length()).toBe(1) + + expect(new Vector2(-1, 1).length()).toBe(Math.sqrt(2)) + }) + }) + + describe('#normalize', () => { + it('should normalize vectors correctly', () => { + expect( + new Vector2(1, 0) + .normalize() + .equalsApproximately(new Vector2(1, 0), 0.000001) + ).toBe(true) + + expect( + new Vector2(1, -1) + .normalize() + .equalsApproximately( + new Vector2(Math.sqrt(2) / 2, -Math.sqrt(2) / 2), + 0.000001 + ) + ).toBe(true) + }) + }) + + describe('#distance', () => { + it('should calculate the distance between two vectors correctly', () => { + expect(new Vector2(0, 0).distance(new Vector2(0, -1))).toBe(1) + + expect(new Vector2(1, 0).distance(new Vector2(0, 1))).toBe(Math.sqrt(2)) + }) + }) + + describe('#dotProduct', () => { + it('should calculate the dot product correctly', () => { + expect(new Vector2(1, 0).dotProduct(new Vector2(0, 1))).toBe(0) + + expect(new Vector2(1, 2).dotProduct(new Vector2(3, 4))).toBe(11) // 1 * 3 + 2 * 4 + }) + }) + + describe('#rotate', () => { + it('should rotate a vector correctly', () => { + expect( + new Vector2(0, -1) + .rotate(Math.PI / 2) + .equalsApproximately(new Vector2(1, 0), 0.000001) + ).toBe(true) + + expect( + new Vector2(1.23, -4.56) + .rotate(Math.PI) + .equalsApproximately(new Vector2(-1.23, 4.56), 0.000001) + ).toBe(true) + }) + }) + + describe('#angleBetween', () => { + it('should calculate the angle between two vectors correctly', () => { + expect(new Vector2(1, 0).angleBetween(new Vector2(0, 1))).toBe( + Math.PI / 2 + ) + + expect(new Vector2(1, 0).angleBetween(new Vector2(1, -1))).toBe( + -Math.PI / 4 + ) + }) + }) +}) diff --git a/data_structures/vectors/vector2.ts b/data_structures/vectors/vector2.ts new file mode 100644 index 00000000..e0b61f16 --- /dev/null +++ b/data_structures/vectors/vector2.ts @@ -0,0 +1,145 @@ +/** + * In mathematics and physics, a vector is an element of a vector space. + * + * The Vector2-class implements 2-dimensional vectors together with various vector-operations. + * @see https://en.wikipedia.org/wiki/Vector_(mathematics_and_physics). + */ + +class Vector2 { + x: number + y: number + + constructor(x: number, y: number) { + this.x = x + this.y = y + } + + /** + * Check for exact vector equality. + * + * @param vector The vector to compare to. + * @returns Whether they are exactly equal or not. + */ + equalsExactly(vector: Vector2): boolean { + return this.x === vector.x && this.y === vector.y + } + + /** + * Check for approximate vector equality. + * + * @param vector The vector to compare to. + * @param epsilon The allowed discrepancy for the x-values and the y-values. + * @returns Whether they are approximately equal or not. + */ + equalsApproximately(vector: Vector2, epsilon: number): boolean { + return ( + Math.abs(this.x - vector.x) < epsilon && + Math.abs(this.y - vector.y) < epsilon + ) + } + + /** + * Vector length. + * + * @returns The length of the vector. + */ + length(): number { + return Math.sqrt(this.x * this.x + this.y * this.y) + } + + /** + * Normalization sets the vector to length 1 while maintaining its direction. + * + * @returns The normalized vector. + */ + normalize(): Vector2 { + const length: number = this.length() + if (length === 0) { + throw new Error('Cannot normalize vectors of length 0') + } + return new Vector2(this.x / length, this.y / length) + } + + /** + * Vector addition + * + * @param vector The vector to be added. + * @returns The sum-vector. + */ + add(vector: Vector2): Vector2 { + const x: number = this.x + vector.x + const y: number = this.y + vector.y + return new Vector2(x, y) + } + + /** + * Vector subtraction + * + * @param vector The vector to be subtracted. + * @returns The difference-vector. + */ + subtract(vector: Vector2): Vector2 { + const x: number = this.x - vector.x + const y: number = this.y - vector.y + return new Vector2(x, y) + } + + /** + * Vector scalar multiplication + * + * @param scalar The factor by which to multiply the vector. + * @returns The scaled vector. + */ + multiply(scalar: number): Vector2 { + const x: number = this.x * scalar + const y: number = this.y * scalar + return new Vector2(x, y) + } + + /** + * Distance between this vector and another vector. + * + * @param vector The vector to which to calculate the distance. + * @returns The distance. + */ + distance(vector: Vector2): number { + const difference: Vector2 = this.subtract(vector) + return difference.length() + } + + /** + * Vector dot product + * + * @param vector The vector used for the multiplication. + * @returns The resulting dot product. + */ + dotProduct(vector: Vector2): number { + return this.x * vector.x + this.y * vector.y + } + + /** + * Vector rotation (see https://en.wikipedia.org/wiki/Rotation_matrix) + * + * @param angleInRadians The angle in radians by which to rotate the vector. + * @returns The rotated vector. + */ + rotate(angleInRadians: number): Vector2 { + const ca: number = Math.cos(angleInRadians) + const sa: number = Math.sin(angleInRadians) + const x: number = ca * this.x - sa * this.y + const y: number = sa * this.x + ca * this.y + return new Vector2(x, y) + } + + /** + * Measure angle between two vectors + * + * @param vector The 2nd vector for the measurement. + * @returns The angle in radians. + */ + angleBetween(vector: Vector2): number { + return Math.atan2(vector.y, vector.x) - Math.atan2(this.y, this.x) + } +} + +export { Vector2 }
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: