-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* chore(comments): update LL comments * feat(stack): implement Stack data structure in TypeScript * test(stack): add test for Stack data structure
- Loading branch information
1 parent
525cf9a
commit 55830a9
Showing
3 changed files
with
250 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import { LinkedList } from '../linked-list'; | ||
import { type TypedEqualityFunction } from '../../utils'; | ||
|
||
class Stack<T> implements Iterable<T> { | ||
private list: LinkedList<T>; | ||
|
||
constructor(equalsFunction?: TypedEqualityFunction<T>) { | ||
if (typeof equalsFunction === 'function') { | ||
this.list = new LinkedList(equalsFunction); | ||
} else { | ||
this.list = new LinkedList(); | ||
} | ||
} | ||
|
||
// HELPERS | ||
/** | ||
* Returns size ~ O(1) | ||
*/ | ||
size(): number { | ||
return this.list.size(); | ||
} | ||
|
||
/** | ||
* Returns true if stack is empty ~ O(1) | ||
*/ | ||
isEmpty(): boolean { | ||
return this.list.isEmpty(); | ||
} | ||
|
||
/** | ||
* Appends values to stack from array ~ O(k) | ||
*/ | ||
fromArray(arr: T[]): Stack<T> { | ||
this.list = this.list.fromArray(arr); | ||
return this; | ||
} | ||
|
||
/* | ||
* Iterator | ||
*/ | ||
|
||
[Symbol.iterator](): Iterator<T> { | ||
return this.list[Symbol.iterator](); | ||
} | ||
|
||
// INSERT | ||
/** | ||
* Adds new element ~ O(1) | ||
* @param {T} element value to add to stack | ||
* @return {boolean} | ||
*/ | ||
push(element: T) { | ||
return this.list.push(element); | ||
} | ||
|
||
// ACCESS | ||
/** | ||
* Gets the value of element at top of stack ~ O(1) | ||
* @returns {T | null} value of top element in stack | ||
*/ | ||
peek(): T | null { | ||
return this.list.peekBack(); | ||
} | ||
|
||
// SEARCH | ||
/** | ||
* Checks if value exists in the stack. ~ O(n) | ||
* @param {T} element value to search for | ||
* @returns {boolean} | ||
*/ | ||
contains(element: T) { | ||
return this.list.contains(element); | ||
} | ||
|
||
// DELETE | ||
/** | ||
* Removes element ~ O(1) | ||
* @return {T | null} value of removed element | ||
*/ | ||
pop(): T | null { | ||
return this.list.pop(); | ||
} | ||
|
||
/** | ||
* Deletes all elements ~ O(1) | ||
*/ | ||
clear() { | ||
this.list.clear(); | ||
} | ||
} | ||
|
||
export { Stack }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
import { Stack } from '../../../src/data-structures/sequences/stack'; | ||
|
||
describe('Stack', () => { | ||
let stack: Stack<number>; | ||
|
||
beforeEach(() => { | ||
stack = new Stack(); | ||
}); | ||
|
||
describe('empty stack', () => { | ||
it('returns null when pop() is called on empty stack', () => { | ||
expect(stack.pop()).toBe(null); | ||
}); | ||
|
||
it('returns null when peek() is called on empty stack', () => { | ||
expect(stack.peek()).toBe(null); | ||
}); | ||
}); | ||
|
||
it('is empty', () => { | ||
expect(stack.isEmpty()).toBe(true); | ||
}); | ||
|
||
it('pushes', () => { | ||
stack.push(1); | ||
expect(stack.size()).toBe(1); | ||
|
||
stack.push(2); | ||
expect(stack.size()).toBe(2); | ||
|
||
stack.push(3); | ||
expect(stack.size()).toBe(3); | ||
}); | ||
|
||
it('finds out if list contains element', () => { | ||
expect(stack.contains(1)).toBe(false); | ||
stack.push(1); | ||
stack.push(2); | ||
stack.push(3); | ||
|
||
expect(stack.contains(1)).toBe(true); | ||
expect(stack.contains(3)).toBe(true); | ||
expect(stack.contains(8)).toBe(false); | ||
}); | ||
|
||
it('pops', () => { | ||
stack.push(1); | ||
stack.push(2); | ||
stack.push(3); | ||
|
||
stack.pop(); | ||
expect(stack.size()).toBe(2); | ||
|
||
stack.pop(); | ||
expect(stack.size()).toBe(1); | ||
|
||
stack.pop(); | ||
expect(stack.size()).toBe(0); | ||
}); | ||
|
||
it('peeks', () => { | ||
stack.push(1); | ||
expect(stack.peek()).toBe(1); | ||
|
||
stack.push(2); | ||
expect(stack.peek()).toBe(2); | ||
}); | ||
|
||
it('clears the stack', () => { | ||
stack.push(1); | ||
stack.push(2); | ||
stack.push(3); | ||
stack.push(4); | ||
stack.clear(); | ||
expect(stack.isEmpty()).toBe(true); | ||
|
||
stack.push(1); | ||
stack.clear(); | ||
expect(stack.isEmpty()).toBe(true); | ||
|
||
stack.clear(); | ||
expect(stack.isEmpty()).toBe(true); | ||
}); | ||
|
||
it('fills a new stack from an array', () => { | ||
stack.fromArray([1, 3, 7, 6]); | ||
|
||
expect(stack.size()).toBe(4); | ||
expect(stack.pop()).toBe(6); | ||
}); | ||
|
||
it('is iterable', () => { | ||
const nums = [1, 2, 3]; | ||
|
||
for (const n of nums) { | ||
stack.push(n); | ||
} | ||
|
||
let i = 0; | ||
for (const n of stack) { | ||
expect(n).toBe(nums[i]); | ||
i += 1; | ||
} | ||
}); | ||
}); | ||
|
||
describe('Stack - complex object', () => { | ||
class Car { | ||
carId: number; | ||
topSpeed: number; | ||
engineSize: number; | ||
|
||
constructor(id: number) { | ||
this.carId = id; | ||
this.topSpeed = 100; | ||
this.engineSize = 100; | ||
} | ||
} | ||
|
||
const sameHeroF = (a: Car, b: Car) => a.carId === b.carId; | ||
|
||
let stack: Stack<Car>; | ||
|
||
beforeAll(() => { | ||
const ferrari = new Car(123); | ||
const peugeot = new Car(456); | ||
const honda = new Car(789); | ||
|
||
stack = new Stack(sameHeroF); | ||
|
||
stack.push(ferrari); | ||
stack.push(peugeot); | ||
stack.push(honda); | ||
}); | ||
|
||
it('checks if stack contains hero', () => { | ||
const knight = new Car(123); | ||
const mage = new Car(789); | ||
|
||
expect(stack.contains(knight)).toBe(true); | ||
expect(stack.contains(mage)).toBe(true); | ||
expect(stack.contains(new Car(246))).toBe(false); | ||
}); | ||
}); |