数组理论基础
数组是存放连续内存空间上的相同数据类型的集合
在JavaScript中,可以在数组中保存不同数据类型的值,因此内存地址并不是连续的,而是采用hash映射的方式
但是现在的JavaScript引擎为了优化JavaScript,会分配一个连续的内存空间给相同数据类型的数组,以达到更好的遍历效果,所以,只要你数组里面存的是相同类型的值,在内存中的地址是连续的
需要注意:
- 数组的下标都是从0开始的
- 数组内存空间的地址是连续的
所以在删除或者增加元素的时候,就难免要移动其他元素的地址
数组方法
JavaScript数组API(含手写)
栈(含手写栈类)
栈是一种遵循后进先出(LIFO)的有序集合
栈方法
- 向栈顶添加元素——push
- 从栈顶删除元素——pop
- 查看栈顶元素——peek
- 检查栈是否为空——isEmpty
- 清空栈元素——clear
基于数组实现栈及其方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| class Stack { constructor() { this.stack = []; } size() { return this.stack.length; } push(val) { this.stack.push(val); return this.stack.length; } pop() { return this.stack.pop(); } peek() { return this.stack[this.stack.length - 1]; } isEmpty() { return !this.stack.length; } clear() { return this.stack = []; } }
|
应用一下吧~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| const stack = new Stack();
stack.push(2); stack.push(3); stack.push(4);
stack.pop();
console.log(stack.isEmpty());
console.log(stack.peek());
stack.pop(); stack.pop();
console.log(stack.isEmpty());
|
基于对象实现栈及其方法
用数组实现Stack是非常方便的,但是如果要在数组中找一个元素,最坏的情况下需要迭代数组的所有位置,也就是时间复杂度是O(n)
另外,数组是一个有序集合,为了保证元素排列有序,它会占用更多的内存空间
使用JavaScript对象存储所有栈元素的优势在于:
- 直接获取元素,占用较少的内存空间
- 保证所有元素按照我们需要的排序
注意:相对于数组版本,对象版本需要实现toString()方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| class Stack { constructor() { this.count = 0; this.stack = {}; } size() { return this.count; } isEmpty() { return this.count === 0; } push(val) { this.stack[this.count] = val; this.count++; return this.count; } pop() { if (this.isEmpty()) { return undefined; } else { const res = this.stack[this.stack.length -1]; this.count--; delete this.stack[this.count]; return res; } } peek() { if (this.isEmpty()) { return undefined; } return this.stack[this.count -1]; } toString() { if (this.isEmpty()) { return ''; } let objString = String(this.stack[0]); for (let i = 1; i < this.count; i++) { objString = `${objString},${this.stack[i]}`; }; return objString; } }
|
应用一下吧~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| const stack = new Stack();
stack.push(2); stack.push(3); stack.push(4);
stack.pop();
console.log(stack.isEmpty());
console.log(stack.peek());
stack.pop(); stack.pop();
console.log(stack.isEmpty());
stack.push(2); stack.push(3); stack.push(4);
console.log(stack.toString());
|
栈应用
- 函数调用
- 表达式求值
- 括号匹配
- 浏览器的前进、后退功能
队列(含手写队列类)
队列是一种遵循先进先出(FIFO)的有序集合
队列方法
- 向队列添加元素——enqueue
- 从队列移除元素——dequeue
- 查看队列头元素——peek
- 检查队列是否为空——isEmpty
- 清空队列——clear
基于数组实现队列及其方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| class Queue{ constructor() { this.queue = []; } size() { return this.queue.length; } enqueue(val) { this.queue.push(val); return this.queue.size(); } dequeue() { return this.queue.shift(); } peek() { return this.queue[0]; } isEmpty() { return !this.queue.length; } clear() { return this.queue = []; } }
|
基于对象实现队列及其方法
基于对象实现队列比数组要难一点,因为对象是根据key来记录索引的,所以需要lowsetCount来记录队头元素的索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| class Queue{ constructor() { this.queue = []; this.count = 0; this.lowsetCount = 0; } size() { return this.count - this.lowsetCount; } enqueue(val) { this.queue[this.count] = val; this.count++; } dequeue() { if (this.isEmpty()) { return undefined; }
const res = this.queue[this.lowsetCount]; delete this.queue[this.lowsetCount]; this.lowsetCount++; return res; } peek() { if (this.isEmpty()) { return undefined; } return this.queue[this.lowsetCount]; } isEmpty() { return !this.size(); } clear() { this.queue = {}; this.count = 0; this.lowsetCount = 0; } toString() { if (this.isEmpty()) { return ''; } let objString = String(this.queue[this.lowsetCount]); for (let i = this.lowsetCount+1; i < this.count; i++) { objString = `${objString},${this.queue[i]}`; }; return objString; } }
|
应用一下吧~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const queue = new Queue();
queue.enqueue(1); queue.enqueue(2); queue.enqueue(3);
console.log(queue.isEmpty());
console.log(queue.peek());
queue.dequeue(); queue.dequeue();
queue.enqueue(4);
console.log(queue.toString());
|
队列应用
双端队列(含手写双端队列类)
双端队列支持同时从后面或者前面添加或者移除元素
双端队列方法
- 从队头添加元素——addFront
- 从队尾添加元素——addBack
- 从队头移除元素——removeFront
- 从队尾移除元素——removeBack
- 查看队头元素——peekFont
- 查看队尾元素——peekBack
- 检查队列是否为空——isEmpty
- 清空队列——clear
基于对象实现队列及其方法
用数组实现较为简单,这里就写了,直接用对象开写!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
| class Deque{ constructor() { this.deque = {}; this.count = 0; this.lowsetCount = 0; } size() { return this.count - this.lowsetCount; } addFront(val) { if (this.isEmpty()) { this.addBack(val); } else if (this.lowsetCount > 0) { this.deque[this.lowsetCount - 1] = val; } else if (this.lowsetCount === 0) { for (let i = this.count; i > 0; i++) { this.deque[this.count] = this.deque[this.count -1]; }; this.count++; this.lowsetCount = 0; this.deque[0] = val; } } addBack(val) { this.deque[this.count] = val; this.count++; } removeFront() { let res = this.deque[this.lowsetCount]; delete this.deque[this.lowsetCount]; this.lowsetCount++; return res; } removeBack() { this.count--; let res = this.deque[this.count]; delete this.deque[this.count]; return res; } peekFront() { return this.deque[this.lowsetCount]; } peekBack() { return this.deque[this.count - 1]; } isEmpty() { return this.count - this.lowsetCount === 0; } clear() { this.queue = {}; this.count = 0; this.lowsetCount = 0; } toString() { if (this.isEmpty()) { return ''; } let objString = String(this.deque[this.lowsetCount]); for (let i = this.lowsetCount+1; i < this.count; i++) { objString = `${objString},${this.deque[i]}`; }; return objString; } }
|
应用一下吧~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const deque = new Deque();
console.log(deque.isEmpty());
deque.addBack(1); deque.addBack(2);
console.log(deque.toString());
deque.addBack(3);
console.log(deque.toString());
console.log(deque.size()); console.log(deque.isEmpty());
deque.removeFront(); console.log(deque.toString());
deque.removeBack(); console.log(deque.toString());
|
双端队列应用
参考
代码随想录_数组基础