栈及其应用

  在使用一个东西之前,得清楚它是什么,才能知道它的用途以及该如何使用。

栈的简介

  栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶(top),相对地,把另一端称为栈底(bottom)。向一个栈插入新元素又称作进栈、入栈或压栈(push),它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈(pop),它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

  栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。栈具有记忆作用,对栈的插入与删除操作中,不需要改变栈底指针。

  进栈与出栈操作如下图:
在这里插入图片描述

应用

  通过上述定义可以知道,栈结构具有后进先出的固有特性,所以可以利用其独特性进行实现应用,如:解决逆波兰表达式问题,括号匹配问题。

逆波兰表达式

  表达式一般由操作数(Operand)、运算符(Operator)组成,例如算术表达式中,通常把运算符放在两个操作数的中间,这称为中缀表达式(Infix Expression),如A+B。

  波兰数学家Jan Lukasiewicz提出了另一种数学表示法,它有两种表示形式:

  把运算符写在操作数之前,称为波兰表达式(Polish Expression)或前缀表达式(Prefix Expression),如+AB;把运算符写在操作数之后,称为逆波兰表达式(Reverse Polish Expression)或后缀表达式(Suffix Expression),如AB+;前后缀表达式的出现是为了方便计算机处理,它的运算符是按照一定的顺序出现,所以求值过程中并不需要使用括号来指定运算顺序,也不需要考虑运算符号(比如加减乘除)的优先级。

  实现逆波兰式的算法,难度并不大,但为什么要将看似简单的中缀表达式转换为复杂的逆波兰式?原因就在于这个简单是相对人类的思维结构来说的,对计算机而言中序表达式是非常复杂的结构。相对的,逆波兰式在计算机看来却是比较简单易懂的结构。因为计算机普遍采用的内存结构是栈式结构,它执行先进后出的顺序。

  本题来自力扣第150题:150. 逆波兰表达式求值 - 力扣(LeetCode)

  题目概要:
在这里插入图片描述

  乍一看题目给人一种很蒙的感觉,可以结合样例来看
在这里插入图片描述

代码实现

Java

  注意,Java自带有栈,所以这里直接可以使用。

class Solution {
    public int evalRPN(String[] tokens) {
        //初始化一个栈
      Stack<Integer> stack = new Stack<Integer>();
      int n = tokens.length;
      for(String token:tokens){
          if(isNumber(token)){
              stack.push(Integer.parseInt(token));
          }else{
              int num2 = stack.pop();
              int num1 = stack.pop();
              switch(token){
                  case "+":
                  stack.push(num1+num2);
                  break;
                  case "-":
                  stack.push(num1-num2);
                  break;
                  case "*":
                  stack.push(num1*num2);
                  break;
                  case "/":
                  stack.push(num1/num2);
              }
          }
      }
        //此时通过一些列的计算,答案便是栈顶元素
      return stack.pop();
    }
    public boolean isNumber(String s){
        return !(s.equals("+")||s.equals("-")||s.equals("*")||s.equals("/"));
    }
}

  完整逻辑代码

public class Main {
	public static void main (String[] args) {
		Scanner sc = new Scanner(System.in);
		//读取字符串
		String s = sc.next();
		//将读取到的字符串分割成字符串数组,方便后续操作
		String[] tokens = s.split("");
		// 创建Solution对象
		Solution solution = new Solution();
		//调用该对象中的方法,并得到运算结果
		int ret = solution.evalRPN(tokens);
		//输出运算结果
		System.out.println(ret);
	}
}
class Solution {
	public int evalRPN(String[] tokens) {
		Stack<Integer> stack = new Stack<Integer>();
		int n = tokens.length;
		for(String token:tokens){
			if(isNumber(token)){
				stack.push(Integer.parseInt(token)); //将字符串转换为数字对象
			}else{
				int num2 = stack.pop();
				int num1 = stack.pop();
				switch(token){
					case "+":
						stack.push(num1+num2);
						break;
					case "-":
						stack.push(num1-num2);
						break;
					case "*":
						stack.push(num1*num2);
						break;
					case "/":
						stack.push(num1/num2);
				}
			}
		}
		return stack.pop();
	}
	public boolean isNumber(String s){ //判断该字符串是否为数字
		return !(s.equals("+")||s.equals("-")||s.equals("*")||s.equals("/"));
	}
}

  运行结果
在这里插入图片描述

括号匹配

  括号匹配,顾名思义,对应的左括号与之对应的右括号相匹配(如,'(‘和’)‘匹配,’[‘和’]‘匹配,’{‘和’}'匹配)。
在这里插入图片描述

代码实现思想:

  用一个栈进行存储左括号,如果遇到右括号则将其对应的左括号弹出,如果右括号在左括号前面或者两个括号数量不相等,则匹配失败,否则匹配成功。

代码实现

public class Main {
	public static void main (String[] args) {
		Scanner sc = new Scanner(System.in);
		//创建字符串
		String s = sc.next();
		// 创建栈
		Stack stack = new Stack<Character>();
		// 判断括号是否匹配
		boolean flag = true;
		for(int i = 0;i<s.length();i++){
			char ch = s.charAt(i);
			if(ch=='('||ch=='{'||ch=='['){
				stack.push(ch);
			}else{
				if(stack.isEmpty()||(char)stack.peek()!=getLeft(ch)){ //如果此时栈为空或栈顶元素右括号不相等,则说明不匹配
					flag = false;
				}
				// 如果匹配则弹出
				stack.pop();
			}
		}
		if(flag&&stack.isEmpty()){ // 如果括号匹配并且栈为空
			System.out.println("括号匹配!");
		}else{
			System.out.println("括号不匹配!");
		}
	}
	public static char getLeft(char ch){ //通过右括号返回其匹配的左括号
		if(ch==')'){
			return '(';
		}else if(ch==']'){
			return '[';
		}
		return '{';
	}
}

  运行结果
在这里插入图片描述
在这里插入图片描述

总结

  栈是一种后进先出的数据结构,合理的利用其特性可以很方便的解决一些特定的问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值