DataStructures_Stack.js

/**
 * @name StackNode
 * @class
 * @classdesc
 * Represents a node to be used in a Stack class
 * 
 * @param {*} [value] - The value to be stored in the node
 * 
 * @property {StackNode} next - The next node in the stack
 * @property {*} value - The value stored in the node
 */
export class Node {
	constructor(value) {
		this.value = value;
		this.next = null;
	}
}

/**
 * @class
 * @name Stack
 * @classdesc
 * Represents a Stack data structure
 * 
 * @see https://en.wikipedia.org/wiki/Stack_(abstract_data_type)
 * 
 * @example
 * new Stack();
 * new Stack("Beep");
 * new Stack([10,20,30]);
 * 
 * @param {Array|*} value - The value to initialize the stack with (optional).
 * 
 * @property {StackNode} top - The first node in the stack
 * @property {Number} size - The number of nodes in the stack
 */
export class Stack {
	constructor(value) {
		this.top = null;
		this.size = 0;

		if (Array.isArray(value)) value.forEach((v) => this.push(v));
		else if (value !== undefined) this.push(value);
	}

	/**
	 * Adds a new value to the top of the stack
	 * 
	 * @example
	 * const s = new Stack([10,20]);
	 * s.push(30); // [10,20,30]
	 * 
	 * @param {Number} value - The value to add.
	 * @returns {Stack} The current Stack instance.
	 */
	push(value) {
		const newNode = new Node(value);

		if (this.size === 0) {
			this.top = newNode;
		} else {
			newNode.next = this.top;
			this.top = newNode;
		}

		this.size++;
		return this;
	}

	/**
	 * Removes the top value from the stack
	 * 
	 * @example
	 * const s = new Stack([10,20,30]);
	 * s.pop(); // [10,20]
	 * 
	 * @param {Boolean} returnNode - Whether to return the node or just the value.
	 * @returns {Stack|*} The current Stack instance.
	 */
	pop(returnNode = false) {
		if (this.size === 0) return undefined;

		const temp = this.top;

		this.top = temp.next;
		this.size--;

		return returnNode ? temp : temp.value;
	}

	/**
	 * Removes all values from the stack
	 * 
	 * @example
	 * const s = new Stack([10,20,30]);
	 * s.clear(); // []
	 * 
	 * @returns {Stack} The current Stack instance.
	 */
	clear() {
		this.top = null;
		this.size = 0;

		return this;
	}

	/**
	 * Returns the first value in the stack
	 * 
	 * @example
	 * const s = new Stack([10,20,30]);
	 * s.peek(); // 10
	 * 
	 * @param {Boolean} returnNode - Whether to return the node or just the value.
	 * @returns {*|StackNode} The value in the first node.
	 */
	peek(returnNode = false) {
		if (this.size === 0) return undefined;
		return returnNode ? this.top : this.top.value;
	}

	/**
	 * Prints the values in the stack
	 * 
	 * @example
	 * const s = new Stack([10,20,30]);
	 * s.print(); // 10,20,30
	 * 
	 * @returns {Stack} The current Stack instance.
	 */
	print() {
		let node = this.top;

		while (node) {
			console.log(node.value);
			node = node.next;
		}

		return this;
	}

	/**
	 * Checks if the stack is empty
	 * 
	 * @example
	 * const s = new Stack();
	 * s.isEmpty(); // true
	 * 
	 * @returns {Boolean} Whether or not the stack is empty.
	 */
	isEmpty() {
		return this.size === 0;
	}

	/**
	 * Returns the number of nodes in the stack
	 * 
	 * @example
	 * const s = new Stack([10,20,30]);
	 * s.toArray(); // [10,20,30]
	 * 
	 * @returns {Number} The number of nodes in the stack.
	 */
	toArray() {
		const arr = [];

		let node = this.top;

		for (let i = 0; i < this.size; i++) {
			arr.push(node.value);
			node = node.next;
		}

		return arr;
	}
}