A stack is an ordered set that follows the principle of last-in-first-out (ILFO). The newly added or deleted elements are stored in the same section of the stack, called the top of the stack, and the bottom of the stack at the other end. In reality, many examples use this data structure, such as a stack of books and stacked plates. Stacks are usually used to save variables, method calls, and, of course, browser history.
Array-based stack
Create classes
class StackArray { constructor() { this.items = []; }
Adding elements to the top of the stack
push(element) { this.items.push(element); }
Remove elements from the top of the stack
pop() { return this.items.pop(); }
View stack top elements
peek() { return this.items[this.items.length - 1]; }
Check if the stack is empty
isEmpty() { return this.items.length === 0; }
Empty stack elements
clear() { this.items = []; }
Convert to an array
toArray() { return this.items; }
Convert to string
toString() { return this.items.toString(); }
stack class based on Javascript object
Create stack class
class Stack { constructor() { this.count = 0;//Record stack size to help us add and delete operations this.items = {}; }
Adding elements
push(element) { this.items[this.count] = element; this.count++; }
Delete elements
pop() { if (this.isEmpty()) { return undefined; } this.count--; const result = this.items[this.count]; delete this.items[this.count]; return result; }
Verify whether a stack is empty and its size
isEmpty() { return this.count === 0; } size() { return this.count; }
View the value at the top of the stack and empty the stack
peek() { if (this.isEmpty()) { return undefined; } return this.items[this.count - 1]; }; clear() { /* while (!this.isEmpty()) { this.pop(); } */ this.items = {}; this.count = 0; };
Convert to string
toString() { if (this.isEmpty()) { return ''; } let objString = `${this.items[0]}`; for (let i = 1; i < this.count; i++) { objString = `${objString},${this.items[i]}`; } return objString; } }
summary
In addition to the toString method, the time complexity of the other methods we create is O(1), which means that we can directly tap into the target element and manipulate it.
Be careful
So far, we have used ES6 grammar class. Because of the characteristics of JavaScript language, classes can not have private attributes like other languages. That is to say, private attributes can be referenced externally and assigned to them. Look at the following code to see:
const stack = new Stack(); console.log(Object.getOwnPropertyNames(stack));//["count","items"] console.log(Object.keys(stack));//["count","items"] console.log(stack.items);//Direct access to private properties
So the problem arises. We just want users to use the attributes or methods we expose. How can we implement private attributes? The author read the summary of his predecessors and wrote it directly.
Protect internal elements of data structures
Underline naming convention
class stack{ constructor(){ this._count = 0; this._items = {}; } };
It's just a convention, depending on the common sense of the developer.
Implementing Symbol Classes with E2015 Limitations
const _items = Symbol('stackItems'); class Stack{ constructor(){ this[_items] = []; } };
Although the basic type of Symbol is immutable, the new Object.getOwnPropertySymbols method added in ES2015 still has access to all Symbol attributes in the form of arrays, but we operate on stacks, and this behavior should not occur. Don't worry. There's a third plan.
Implementing Classes with WeakMap of ES2015
const items = new WeakMap(); class Stack{ constructor(){ items.set(this,[]); }, push(element){ const s = items.get(this); s.push(element); } }
In this way, we have implemented a completely private property, but the readability of the code is really too bad for the author. I don't know how you feel about it.
Practice of stack
Binary Conversion Algorithms
function baseConverter(decNumber, base) { const remStack = new Stack(); const digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; let number = decNumber; let rem; let baseString = ''; if (!(base >= 2 && base <= 36)) { return ''; } while (number > 0) { rem = Math.floor(number % base); remStack.push(rem); number = Math.floor(number / base); } while (!remStack.isEmpty()) { baseString += digits[remStack.pop()]; }
Balanced parentheses algorithm
function parenthesesChecker(symbols) { const stack = new Stack(); const opens = '([{'; const closers = ')]}'; let balanced = true; let index = 0; let symbol; let top; while (index < symbols.length && balanced) { symbol = symbols[index]; if (opens.indexOf(symbol) >= 0) { stack.push(symbol); } else if (stack.isEmpty()) { balanced = false; } else { top = stack.pop(); if (!(opens.indexOf(top) === closers.indexOf(symbol))) { balanced = false; } } index++; } return balanced && stack.isEmpty(); }