2020年6月4日下午,前端小伙伴胡利朋同学分享了数据结构中栈和队列的 JavaScript 实现,收获良多,在此做下笔记,也自己实现一下栈和队列这两个数据结构。
1.栈
1.1 栈的定义
栈是一种特殊的线性表,仅能够在栈顶进行操作,有着后进先出的特性 。
1.2 栈的 JavaSaript 实现
1.2.1数据存储
- 数组
- 链表
栈这样的数据结构,一般可以用数组或者链表进行数据的存储。在JavaScript中,数组最常用,也是最熟悉的,下面我们就用数组来实现栈这个数据结构。
1.2.2栈的方法
栈的方法主要有以下几个:
- 入栈
- 出栈
- 返回栈顶元素
- 判空
- 清空
- 返回大小
- 打印所有元素
具体实现:
class Stack {
constructor() {
// 定义一个数组存储数据,数组头为栈底,尾为栈顶
this.stack = [];
}
// 入栈:添加一个或多个元素到栈顶
inStack(...args) {
this.stack.push(...args);
}
// 出栈:移除栈顶的元素,同时返回被移除的元素
outStack() {
return this.stack.pop();
}
// 返回栈顶元素
stackTop() {
return this.stack[this.stack.length - 1];
}
// 判空
isEmpty() {
return this.stack.length === 0;
}
// 清空
clearStack() {
this.stack = [];
}
// 返回大小
stackSize() {
return this.stack.length;
}
// 打印所有元素
printStack() {
console.log(this.stack.toString());
}
}
// 测试
let new_stack = new Stack();
// 入栈
new_stack.inStack(1, 2, 3, 4)
console.log('打印入栈之后栈中所有元素')
new_stack.printStack();
console.log('返回栈顶元素', new_stack.stackTop());
console.log('返回栈的大小', new_stack.stackSize());
console.log('判断栈是否为空', new_stack.isEmpty());
console.log('出栈', new_stack.outStack());
console.log('打印出栈之后栈中所有元素')
new_stack.printStack();
1.3 栈的应用练习
创建好栈这个数据结构之后,很多算法的时间都会变得很简单,下面就以判断括号合法性这一算法来举例说明。
判断括号的合法性
举例:
- ‘(()()((((()))))(()))’ —合法的括号,左右配对
- ‘())())(()()(()))()’ —不合法的括号,左右不配对
算法实现:
// 栈的应用练习
// 判断括号的合法性
// 整体思路:
// 如果只有一个括号,直接不合法
// 如果第一个是")",直接不合法
// 创建一个栈,遍历字符串,如果是"(",将其入栈,当碰到")"的时候,将一个"("出栈,当没有"("可以出栈和")"匹配,直接不合法,最后栈不为空(还有"("没有被匹配),直接不合法
function isLegalBracket(str) {
// 输入的字符串为空,返回提示信息
if (str.length === 0) {
return '请输入要检验的字符串';
}
// 只有一个括号,返回false
if (str.length === 1) {
return false;
}
// 第一个是")",返回false
if (str[0] === ")") {
return false;
}
let stack = new Stack;
for (let i = 0; i < str.length; i++) {
if (str[i] === "(") {
stack.inStack(str[i]);
}
if (str[i] === ")") {
if (stack.isEmpty()) {
return false;
} else {
stack.outStack();
}
}
}
return stack.isEmpty();
}
console.log("'(()()((((()))))(()))'中括号的合法性为:",isLegalBracket('(()()((((()))))(()))'))
console.log("'())())(()()(()))()'中括号的合法性为:",isLegalBracket('())())(()()(()))()'))
栈除了上面的应用,还可以实现一些操作的撤回以及重做,都是很方便的,碰到需要做撤回的功能,小伙伴们可以考虑用栈来存储数据哦!
2. 队列
2.1 队列的定义
队列是一种特殊的线性表,其特殊之处在于,它只允许你在队列的头部删除元素,在队列的末尾添加新的元素。有着先进先出的特性。
2.2 队列的 JavaScript实现
2.2.1 数据存储
- 数组
- 链表
同栈一样,我们经常用数组或者链表来存储队列这一数据结构,下面来看看用数组怎么存储队列吧!
2.2.2 队列的方法
和栈类似,队列中一般也都有以下方法
- 队尾添加
- 队首删除
- 返回队首元素
- 判断队列是否为空
- 清空队列
- 返回队列的大小
- 打印队列中所有的元素
具体实现
class Queue {
constructor() {
// 定义一个数组存储数据,数组头为队首,尾为队尾
this.queue = [];
}
// 入队:添加一个或多个元素到队列中
inQueue(...args) {
this.queue.push(...args);
}
// 出队:移除队首的元素,同时返回被移除的元素
outQueue() {
return this.queue.shift();
}
// 返回队首元素
queueTop() {
return this.queue[0];
}
// 判空
isEmpty() {
return this.queue.length === 0;
}
// 清空
clearQueue() {
this.queue = [];
}
// 返回大小
queueSize() {
return this.queue.length;
}
// 打印所有元素
printQueue() {
console.log(this.queue.toString());
}
}
2.3 队列的应用练习
使用队列这一数据结构,也可以让我们很多方法变得很简单,比如我们要查询斐波那契数列中第200个数是什么,就可以用队列很方便的算出来。
斐波那契数列:一个数列,从第三项开始,以后的每一项为前两项的和
例:1,1,2,3,5,8,13,21,34…
// 斐波那契数列
function fibonacci(n) {
let queue = new Queue();
let index = 0;
// 先放⼊入斐波那契序列列的前两个数值
queue.inQueue(1);
queue.inQueue(1);
while (index < n - 2) {
// 出队列列⼀一个元素
let del_item = queue.outQueue();
// 取队列列头部元素
let head_item = queue.queueTop();
let next_item = del_item + head_item;
// 将计算结果放⼊入队列列
queue.inQueue(next_item);
index += 1;
}
queue.outQueue();
return queue.queueTop();
};
console.log(fibonacci(4))
console.log(fibonacci(5))
console.log(fibonacci(6))
console.log(fibonacci(7))
console.log(fibonacci(8))
console.log(fibonacci(99))
除此以外,在写前端交互的时候,页面上会有很多弹窗,我们也可以用队列来存储,这样,弹窗就会按照出现的顺序一个一个弹出来。在后端开发中,服务器的消息队列,也经常使用队列这种数据结构。
2.4 队列的变形—双端队列
2.4.1 定义
双端队列(deque,或称 double-ended queue)是一种允许我们同时从前端和后端添加和移除元素的特殊队列。(看这个定义,双端队列是不是特别像JavaSctipt中的数组?)
2.4.2 实现
2.4.3 应用
回文检查器
回文字符串:当一个字符串是一个中心对称的字符串,我们就称这个字符串为回文字符串
例:”a”
例:”aba”
例:”abba”
// 回文检查器
function palChecker(str) {
// 创建一个双端队列,将字符串中的字符,依次添加到双端队列中
let arr = str.split('');
// 假定是回文字符串
let isPalindrome = true;
// 当至少有一个字符并且满足首位相等,则循环
while (arr.length > 1 && isPalindrome) {
let first = arr.shift();
let last = arr.pop();
if (first !== last) {
isPalindrome = false;
}
}
return isPalindrome;
}
console.log(palChecker('abba'))
队列还有其他的变形,如
,小伙伴们可以自行了解,这里就不再展开解释。