Stack Data Structure
August 17, 2022Introduction
The Stack Data Structure is similar to the Queue. The difference is that Stack obeys the LIFO (Last In First Out) principle, and Queue, on the other hand, obeys the FIFO (First In First Out) principle.
Why is it important to know this? Well, if you know how to implement a Queue, you know how to implement a Stack; You need to change a few methods naming and use different methods on the array, but the rest is mostly the same.
Stack operations
The Stack has a few basic operations that are described below. It does not mean you cannot add any other operation if you need one.
push
Adds an item to the top of the Stack.
pop
Removes the top item (latest) of the Stack.
peek
Returns the top item (latest) of the Stack.
length
Returns the length of the Stack.
isEmpty
Returns true if the Stack is empty, false otherwise.
Implementation
TypeScript definition
// as we want to support various item types, we are making our type `CreateStackReturnType` generic by accepting a `T` type variabletype CreateStackReturnType<T> = {// adds an item to the top of the Stack, do not return anythingpush: (item: T) => void// removes the top item (latest) of the Stack, do not return anythingpop: () => void// returns the top item (latest) of the Stackpeek: () => T// returns the length of the Stacklength: number// returns true if the Stack is empty, false otherwiseisEmpty: () => boolean}
Factory function implementation
// `createStack` factory function accepts generic `T` type variable// `T` type variable will be used within `CreateStackReturnType` and inside of factory functionexport function createStack<T>(): CreateStackReturnType<T> {// the Stack itself will be an array of items// the type of item is dynamic, controlled by the `T` type variableconst stack: Array<T> = []return {push() {},pop() {},peek() {},// we need to use `get` to access the latest `length` property of the Stackget length() {},isEmpty() {},}}
Adding tests
import { createStack } from './stack'describe('stack', () => {const stack = createStack<string>()it('should be empty initially', () => {// initially stack is emptyexpect(stack.length).toBe(0)expect(stack.isEmpty()).toBe(true)expect(stack.peek()).toBeUndefined()})it('should push and pop', () => {stack.push('First item')stack.push('Second item')stack.push('Third item')expect(stack.length).toBe(3)expect(stack.isEmpty()).toBe(false)expect(stack.peek()).toBe('Third item')stack.pop()expect(stack.length).toBe(2)expect(stack.isEmpty()).toBe(false)expect(stack.peek()).toBe('Second item')stack.pop()expect(stack.length).toBe(1)expect(stack.isEmpty()).toBe(false)expect(stack.peek()).toBe('First item')stack.pop()expect(stack.length).toBe(0)expect(stack.isEmpty()).toBe(true)expect(stack.peek()).toBeUndefined()})})
Implement push
export function createStack<T>(): CreateStackReturnType<T> {const stack: Array<T> = []return {push(item: T) {// push method append an item to the top of the stackstack.push(item)},pop() {},peek() {},get length() {},isEmpty() {},}}
Implement pop
export function createStack<T>(): CreateStackReturnType<T> {const stack: Array<T> = []return {push(item: T) {// push method append an item to the top of the stackstack.push(item)},pop() {// pop method removes the last item from the stackstack.pop()},peek() {},get length() {},isEmpty() {},}}
Implement peek
export function createStack<T>(): CreateStackReturnType<T> {const stack: Array<T> = []return {push(item: T) {// push method append an item to the top of the stackstack.push(item)},pop() {// pop method removes the last item from the stackstack.pop()},peek() {// peek method returns the last item from the stackreturn stack[Stack.length - 1]},get length() {},isEmpty() {},}}
Implement length
export function createStack<T>(): CreateStackReturnType<T> {const stack: Array<T> = []return {push(item: T) {// push method append an item to the top of the stackstack.push(item)},pop() {// pop method removes the last item from the stackstack.pop()},peek() {// peek method returns the last item from the stackreturn stack[Stack.length - 1]},get length() {// length method returns the length of the stackreturn stack.length},isEmpty() {},}}
Implement isEmpty
export function createStack<T>(): CreateStackReturnType<T> {const stack: Array<T> = []return {push(item: T) {// push method append an item to the top of the stackstack.push(item)},pop() {// pop method removes the last item from the stackstack.pop()},peek() {// peek method returns the last item from the stackreturn stack[Stack.length - 1]},get length() {// length method returns the length of the stackreturn stack.length},isEmpty() {// returns true if the Stack is empty, false otherwisereturn Stack.length === 0},}}
Complete Implementation
type CreateStackReturnType<T> = {isEmpty: () => booleanlength: numberpeek: () => Tpop: () => voidpush: (item: T) => void}export function createStack<T>(): CreateStackReturnType<T> {const stack: Array<T> = []return {isEmpty() {return stack.length === 0},get length() {return stack.length},peek() {return stack[stack.length - 1]},pop() {stack.pop()},push(item: T) {stack.push(item)},}}
Conclusion
As you may see, the Stack implementation is straightforward and almost the same as the implementation of the Queue.
Have you found any bugs, or do you have any questions? Feel free to reach out on Twitter.
If you do not want to miss the next article, click on the follow button!