认识栈结构

307 阅读3分钟

认识栈结构和特性

相比较数组而言,栈是一种受限的线性结构。

栈结构示意图

1675672489936.png

栈,一种受限的线性结构,后进先出(LIFO)

  • 仅允许在一端进行插入和删除运算。这一端叫做栈顶,相对的,把另一端叫做栈底。
  • 后进先出表示后进入的元素,第一个弹出栈空间。类似于电梯。
  • 向一个栈插入新元素又称为进栈、入栈或压栈。
  • 从一个栈删除元素又称作出栈或退栈。

生活中类似于栈的

  • 进出电梯

栈结构面试题

/* 面试题目:
   有六个元素6,5,4,3,2,1 的顺序进栈,问下列哪一个不是合法的出栈序列?( )
   
   A. 5 4 3 6 1 2  B. 4 5 3 2 1 6  C. 3 4 6 5 2 1 D. 2 3 4 1 5 6 
   答案: C
   解析
   A答案: 65进栈, 5出栈, 4进栈出栈, 3进栈出栈, 6出栈, 21进栈, 1出栈, 2出栈
   B答案: 654进栈,45出栈,3进栈出栈,2进栈出栈,1进栈出栈,6出栈
   D答案: 65432进栈,2出栈,3出栈,4出栈,1进栈出栈,5出栈,6出栈
/*

栈结构的实现

实现栈结构有两种比较常见的方式:

  • 基于数组实现
  • 基于链表实现

我们这里先基于数组实现栈结构,基于链表结构的后面再补充。

创建栈的类

class ArrayStack<T> {
    private data: T[] = [];
}
  • 创建一个Stack类,可以定义一个泛型类。
  • 在构造函数中,定义了一个数组类型的变量,这个变量可以用于保存当前栈对象
  • 之后的进栈还是出栈操作,都是从数组中添加和删除元素
  • 栈有一些相关的操作方法,通常无论是什么语言,操作都是比较类似的。

栈的操作

栈常见有哪些操作呢?

  • push(element): 添加一个新元素到栈顶位置。
  • pop(): 移除栈顶元素,同时返回被移除的元素
  • peek(): 返回栈顶元素,不对栈做任何修改
  • isEmpty(): 如果栈里没有任何元素就返回true,否则返回false
  • size(): 返回栈里面元素的个数,和数组的length属性很类似。

现在我们在类中实现这些方法:

class ArrayStack<T> {
    private data: T[] = [];
    
    push(element: T){
        this.data.push(element);
    }
    
    pop(): T | undefined {
        return this.data.pop();
    }
    
    peek(): T | undefined {
        
    }
    isEmpty(): boolean {
        return this.data.length === 0;
    }
    size(): number {
        return this.datat.length;
    }
}

面试题

一、十进制转二进制

现实生活中,我们主要使用十进制。但在计算科学中,二进制非常重要,因为计算机里所有的内容都是用二进制数字表示的(0和1)。没有十进制和二进制相互转化的能力,与计算机交流就很困难。

要把十进制转化成二进制,我们可以将该十进制数除以2(二进制是满二进一)并对商取整,直到结果是0为止。举个例子,把十进制的数10转化为二进制的数,大致过程是如下这样的。

1675871692691.png

代码如下:

function decimalToBinary(num: number): string {
  // 先创建一个栈
  const stack = new ArrayStack<number>();
  while (num > 0) {
    // 循环体
    const remainder = num % 2;
    stack.push(remainder);
    num = Math.floor(num / 2);
  }
  // 依次出栈
  let binary = "";
  while (!stack.isEmpty()) {
    binary += stack.pop();
  }
  return binary;
}

有效的括号

给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须一正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。
function isValid(s: string): boolean {
  // 1. 创建一个栈
  const stack = new ArrayStack<string>();
  // 循环整个字符串
  for (let i = 0; i < s.length; i++) {
    const element: string = s[i];
    switch (element) {
      case "(":
        stack.push(")");
        break;
      case "{":
        stack.push("}");
        break;
      case "[":
        stack.push("]");
        break;
      default:
        if(element !== stack.pop()){
          return false;
        }
        break;
    }
  }
  // 最后栈不能为空
  return stack.isEmpty();
}