摘要
本文将介绍栈数据结构的概念、基本操作以及如何使用 JavaScript 实现栈。同时也讲述了栈在解决问题时的应用场景及示例
栈的介绍
栈是一种常见的数据结构,它遵循"先进后出"(Last-In-First-Out,LIFO)的原则,是只能在一端进行插入和删除的线性表。通常用于解决需要按照特定顺序处理数据的问题,例如数制间的转换、回文序列判断、括号匹配、浏览器前进后退等。
栈的基本操作
在实现栈之前,我们先了解下栈的基本操作,包括:
1.入栈(push):将元素添加到栈的顶部。
2.出栈(pop):从栈的顶部移除元素,并返回被移除的元素。
3.查看栈顶元素(peek):返回栈顶的元素,但不对栈进行修改。
4.判断栈是否为空(isEmpty):检查栈是否为空,如果栈中没有任何元素,则返回true,否则返回false。
5.获取栈的大小(size):返回栈中元素的个数。
6.清空栈(clear):移除栈中的所有元素。
栈的 JavaScript 实现
在 JavaScript 中,我们可以使用数组或链表来实现栈。如下采用数组方式实现一个简单的栈类,该类提供了操作栈内元素的基本方法
class Stack {
constructor() {
this.items = []; // 使用数组来存储栈中的元素
}
// 入栈操作
push(element) {
this.items.push(element);
}
// 出栈操作
pop() {
if (this.isEmpty()) {
return "栈为空";
}
return this.items.pop();
}
// 返回栈顶元素
peek() {
if (this.isEmpty()) {
return "栈为空";
}
return this.items[this.items.length - 1];
}
// 判断栈是否为空
isEmpty() {
return this.items.length === 0;
}
// 返回栈的大小
size() {
return this.items.length;
}
// 清空栈
clear() {
this.items = [];
}
}
// 使用示例
const stack = new Stack();
stack.push(1);
stack.push(2);
console.log(stack.peek()); // 2
console.log(stack.pop()); // 2
stack.clear();
console.log(stack.isEmpty()); // true
栈的应用场景
1 数制间转换
将一个数字从一种数制转换成另一种数制:将十进制数的每一位的余数入栈,然后从栈中依次弹出每一位数字,构建转换后的数。(思路参考:短除法-除 N 进制取余,逆序排列)
function decimalToBase(decimalNumber, base) {
const stack = new Stack(); // 创建一个空栈来存储转换后的数字的每一位
let remainder;
while (decimalNumber > 0) {
remainder = decimalNumber % base; // 求余数
stack.push(remainder); // 将余数入栈
decimalNumber = Math.floor(decimalNumber / base); // 整除
}
let convertedNumber = "";
while (!stack.isEmpty()) {
convertedNumber += stack.pop(); // 从栈中弹出每一位数字,构建转换后的数
}
return convertedNumber;
}
// 使用示例
console.log(decimalToBase(10, 2)); // "1010",将十进制数 10 转换为二进制
console.log(decimalToBase(125, 8)); // "175",将十进制数 125 转换为八进制
2 回文序列
回文是指一个单词、短语或数字从前往后或从后往前写都是一样的,如:单词 level、dad。回文在文学、密码学等都有一定重要性。在编程中,判断一个字符串是否是回文也是一个常见问题。
使用栈可以轻松判断一个字符串是否是回文:将拿到的字符串从左至右压栈,等所有字符串入栈后,通过持续弹出栈就可以得到一个反转后的字符串,比较两个字符串,如果它们相等,就是一个回文
function isPalindrome(str) {
const stack = new Stack();
const arr = str.split(""); // 将字符串转换为数组
// 将数组的每个元素入栈
for (let i = 0; i < arr.length; i++) {
stack.push(arr[i]);
}
// 从栈中逐个弹出元素,构建逆序字符串
let reverseStr = "";
while (!stack.isEmpty()) {
reverseStr += stack.pop();
}
// 将逆序字符串与原字符串进行比较
return str === reverseStr;
}
// 使用示例
console.log(isPalindrome("abcba")); // true
console.log(isPalindrome("hello")); // false
3 括号匹配
使用栈来检查表达式中的括号是否匹配:当遇到左括号时,我们将其入栈,当遇到右括号时,我们从栈中弹出一个左括号进行匹配。如果在遍历完整个表达式后,栈为空,则说明括号匹配成功。
function isBracketBalanced(expression) {
const stack = new Stack(); // 创建一个空栈来存储左括号
for (let i = 0; i < expression.length; i++) {
const char = expression[i];
if (char === "(") {
stack.push(char); // 遇到左括号,将其入栈
} else if (char === ")") {
if (stack.isEmpty()) {
return false; // 遇到右括号,如果栈为空,则括号不匹配
}
stack.pop(); // 遇到右括号,从栈中弹出一个左括号进行匹配
}
}
return stack.isEmpty(); // 如果栈为空,则括号匹配成功
}
// 使用示例
console.log(isBracketBalanced("((()))")); // true
console.log(isBracketBalanced("(()))")); // false
4 浏览器前进后退
class BrowserHistory {
constructor() {
this.backStack = new Stack(); // 后退栈
this.forwardStack = new Stack(); // 前进栈
}
// 访问新页面
visit(url) {
this.backStack.push(url); // 将新页面推入后退栈
this.forwardStack.clear(); // 清空前进栈
}
// 后退
back() {
if (this.backStack.size() <= 1) {
return "无法后退";
}
const currentUrl = this.backStack.pop(); // 弹出当前页面
this.forwardStack.push(currentUrl); // 将当前页面推入前进栈
return this.backStack.peek(); // 返回上一个页面
}
// 前进
forward() {
if (this.forwardStack.isEmpty()) {
return "无法前进";
}
const currentUrl = this.forwardStack.pop(); // 弹出当前页面
this.backStack.push(currentUrl); // 将当前页面推入后退栈
return currentUrl; // 返回下一个页面
}
}
// 使用示例
const browser = new BrowserHistory();
browser.visit("https://www.example.com/page1");
browser.visit("https://www.example.com/page2");
browser.visit("https://www.example.com/page3");
console.log(browser.back()); // "https://www.example.com/page2"
console.log(browser.back()); // "https://www.example.com/page1"
console.log(browser.forward()); // "https://www.example.com/page2"
console.log(browser.forward()); // "https://www.example.com/page3"
console.log(browser.forward()); // "无法前进"
总结
本文介绍了如何使用 JavaScript 实现栈数据结构,同时简单讲述了栈的使用场景。希望本文对您理解栈的实现和应用有所帮助,同时欢迎大家批评指正~