JavaScript 实现数据结构-栈

125 阅读4分钟

摘要

本文将介绍栈数据结构的概念、基本操作以及如何使用 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 实现栈数据结构,同时简单讲述了栈的使用场景。希望本文对您理解栈的实现和应用有所帮助,同时欢迎大家批评指正~