用JavaScript描述栈

121 阅读2分钟

1. 对栈的操作

栈是一种后入先出(LIFO, last-in-first-out)的数据结构。

对栈的两个主要操作: 一个将元素压入栈,一个将元素弹出栈。入栈使用push()方法,出栈使用pop()方法。

另外常用操作是预览栈顶的元素。pop()方法虽然可以访问栈顶元素,但是,栈顶元素会被删除掉,所以我们需要peek()只返回栈顶元素,而不删除栈顶元素。

为了记录栈顶元素的位置,需要使用变量top。

clear()方法清除栈内所有元素,length()方法记录栈内元素个数,empty是否为空。

2. 栈的实现

我们可以定义Stack类的构造函数

function Stack() {
    this.dataStore = []
    this.top = 0
}
Stack.prototype.push = function(element) {
    this.dataStore[this.top ++] = element
}

Stack.prototype.pop = function(element) {
   if(this.top > 0) {
        this.top --
   }
   return this.dataStore.pop()         
}

Stack.prototype.peek = function() {
   return this.dataStore[this.top - 1]
}

Stack.prototype.length = function() {
   return this.top
}

Stack.prototype.clear = function() {
   this.dataStore = []
   this.top = 0
}

Stack.prototype.empty = function() {
   return !!this.top
}

测试Stack类的实现

var s = new Stack();
s.push("David");
s.push("Raymond");
s.push("Bryan");
console.log("length: " + s.length());
console.log(s.peek());
var popped = s.pop();
console.log("The popped element is: " + popped);
console.log(s.peek());
s.push("Cynthia");
console.log(s.peek());
s.clear();
console.log("length: " + s.length());
console.log(s.peek());
s.push("Clayton");
console.log(s.peek());

3. 使用Stack类

3.1 进制间的相互转换

算法如下:

  • 最后一位为 n % b,将此位压入栈。
  • 使用n / b代替 n。
  • 重复步骤1,2。直到 n <= 0,且没有余数。
  • 持续将栈的元素弹出,直到为空为止,将这些元素排序,拼接成字符串。
function mulBase(num, base) {
  if(num <= 0) {
    return num 
  } 
  var s = new Stack()
  do {
    s.push(num % base)
    num = Math.floor(num / base)
  } while(num > 0)
  var converted = ''
  while(s.length()) {
    converted += s.pop()
  } 
  return converted 
}
3.2 回文

回文指这样的一种现象: 'dad', 'racecar',从前往后写和从后往前写都一样。

使用栈可以轻松判断字符串是否是回文。

function isPalindrome(word) {
    var s = new Stack()
    for(let i = 0; i < word.length; i ++) {
        s.push(word[i])    
    }
    var rword = ''
    while(s.length()) {
        rword += s.pop()    
    }
    return word === rword
}
3.3 递归演示

用栈可以演示模拟递归的过程。

例如5的阶乘: 5! = 5 * 4 * 3 * 2 * 1;

递归函数:

function factorial(n) {
    if(n === 0) {
        return 1    
    } else {
        return n * factorial(n - 1)    
    }
}

使用栈模拟递归的过程

function fact(n) {
    var s = new Stack()
    while(n > 1) {
        s.push(n --)    
    }
    var product = 1
    while(s.length()) {
        product *= s.pop()    
    }
    return product
}
3.4 栈可以用来判断一个算术表达式中的括号是否匹配。编写一个函数,该函数接受一个算术表达式作为参数,返回表达式中的括号是否匹配。下面是一个括号不匹配的算术表达式的例子:2.3 + 23 / 12 + (3.14159×0.24。
function check(expression) {
    var s = new Stack()
    for(let i = 0; i< expression.length; i ++) {
        if(expression[i] === '(') {
            s.push('(')        
        }
        if(expression[i] === ')') {
            if(s.length()) {
                s.pop()            
            }  else {
                return false            
            }      
        } 
    }
    return !s.length()
}