数据结构之动态数组线性表--栈

栈的定义

栈是限定在表尾进行插入和删除操作的线性表(底层也是动态数组),把允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),不含任何元素的栈叫做空栈,栈又称为后进先出的线性表,简称LIFO结构,栈本身就是一个线性表,其数据元素具有线性关系,只不过他是一种特殊的关系

栈的插入操作,叫做进栈,也称为压栈,入栈

栈的删除操作,叫做出栈,也称为弹栈

因为我们之前实现过线性表ArrayList,栈的底层也是动态数组,所以我们可以将栈的底层也变为线性表ArrayList来实现

Stack接口的实现

package List接口实现;
//支持泛型,继承Iterable接口
public interface Stack<E> extends Iterable<E> {
    //获取栈的容量
     public int size();
     //判断栈是否为空
     public boolean isEmpty();
     //进栈一个元素
    public void push(E element);
    //弹栈一个元素
    public E pop();
    //弹栈一个元素并且返回这个元素
    public E peek();
    //清空当前这个栈
    public void clear();
}

ArrayStack类实现Stack接口

package 动态数组;

import List接口实现.Stack;

import java.util.Iterator;

public class ArrayStack<E> implements Stack<E> {
    //栈的内部就是由一个线性表来实现
    private ArrayList<E> list;
    //创建一个默认容量的栈(默认容量的线性表)
    public ArrayStack(){
        list = new ArrayList<E>();
    }
    //由用户指定一个容量的线性表
    public ArrayStack(int capacity){
        list=new ArrayList<>(capacity);
    }
    //获取栈中有效元素的个数
    @Override
    public int size() {
        //线性表中有多少个有效元素,栈中就有多少个有效元素
        return list.size();
    }
//判断栈是否为空
    @Override
    public boolean isEmpty() {
        return list.isEmpty();
    }
 //入栈一个元素(在线性表的表尾添加一个元素)
    @Override
    public void push(E element) {
        list.add(element);//默认在表尾添加元素

    }
//弹栈一个元素并返回(在线性表的表尾删除一个元素)
    @Override
    public E pop() {
        return list.remove(list.size()-1);
    }
  //获取 当前的栈顶元素(不删除)
    @Override
    public E peek() {
        return list.get(list.size()-1);
    }
//清空栈就是清空线性表
    @Override
    public void clear() {
     list.clear();
    }
    //获取底层线性表的迭代器
    @Override
    public Iterator<E> iterator() {
        return list.iterator();
    }
    public String toString(){
        StringBuilder sb =new StringBuilder(String.format("ArrayList:%d/%d[",size(),list.getCapacity()));
        if(isEmpty()){
            sb.append("]");//ArrayList:0/10[]
        }
        else{//ArrayList:0/10[1,2,3,4,5]
            for(int i=0;i<size();i++){
                sb.append(list.get(i));
                if(i!=size()-1){
                    sb.append(',');
                }
                else{
                    sb.append(']');
                }
            }

        }
        return sb.toString();
    }
}

栈的应用

十进制转十六进制

需求:输入一个非负的十进制整数,打印输出与其等值的十六进制数

package 动态数组;
import java.util.Scanner;
//十进制转十六进制
public class DecToHex {
    public static void main(String[] args) {
        //1,获取用户输入一个非负的整数
        Scanner input =new Scanner(System.in);
        System.out.println("Enter a number");
        int  number =input.nextInt();
        //2,创建一个栈来存储余数
        ArrayStack<Character>  stack =new ArrayStack<>();
        //3,开始计算余数
        int mod;
        while(number!=0){
             mod =number%16;//获取一个余数0-9或者10-15--->A-F
            if(mod<10){//数字0-9
                //'0'+3表示字符0之后第三个位置的字符编码,同理'3'-'0'=3
                stack.push((char)('0'+mod));
            }
            else{
                //数字10-15-->A-F
                //'A'+15-10='A'+5表示的是字符A之后第5个位置的字符F的编码
                stack.push((char)('A'+mod-10));
            }
            number/=16;
          //4,按照顺序弹栈即可
            while(!stack.isEmpty()){
                System.out.print(stack.pop());
            }

        }

    }
}

 十六进制转十进制

package 动态数组;
import java.util.Scanner;
public class HexToDec {
    public static void main(String[] args) {
        //1,获取用户的输入,输入一个十六进制的字符串
        Scanner scanner =new  Scanner(System.in);
        System.out.println("Enter a hex string");
        String hex =scanner.nextLine();
        //2,创建一个栈,存储一个数字
        ArrayStack<Character> stack =new ArrayStack<>();
        //3,将字符串中的字符依次进栈
        for(int i=0;i<hex.length();i++){
            stack.push(hex.charAt(i));
        }
        //4,依次弹栈,并累加计算的结果
        int sum =0;
        int exponent =0;//幂数
        int  c;
        while(!stack.isEmpty()){
            c=stack.pop();
            sum+=getNumber(c)*Math.pow(16,exponent);
            //exponent表示幂数
            exponent++;
        }
        System.out.println(sum);
    }
    private static int getNumber(int c) {
        //验证字符是否合法
    if(!('0'<=c && c<='9'||c>='A'&&c<='F')){
         throw  new IllegalArgumentException("字符错误");
    }
    //转换数字字符为数字
   if(c>='0'&&c<='9'){
       return c-'0';
   }
   //转换字母字符为数字
   else{
       return c-'A'+10;
   }
    }
}

用栈来判断回文

package 动态数组;
import java.util.Scanner;
public class 判断回文 {
    public static void main(String[] args) {
        //判断回文
        //1,获取用户的输入字符串
        Scanner input =new Scanner(System.in);
        System.out.println("Enter a text");
        String s=input.nextLine();
        //2.创建一个栈
        ArrayStack<Character> stack =new ArrayStack<>();
        //3,开始遍历遍历字符串,并做出出栈和入栈的操作
        char c;
        for(int i=0;i<s.length();i++){
            //当前字符串的长度是否奇数,如果是奇数的话,直接跳过此迭代
            if(s.length()%2==1 && i==s.length()/2){
              continue;
            }
            c=s.charAt(i);
            //4,如果是空栈,直接放元素
            if(stack.isEmpty()){
                stack.push(c);
            }
            //5,如果不为空,将元素弹出来进行比较
            else{
                if(c==stack.peek()){
                    stack.pop();//相等的就相消
                }
                else{
                    stack.push(c);//不相等就往栈里面放
                }
            }
        }
        //栈是空,说明相消完了,说明是匹配的
        if(stack.isEmpty()){
            System.out.println("是回文字符串");
        }
        else{
            //栈不为空,就没有相消完,说明不是回文
            System.out.println("不是回文字符串");
        }
    }
}

匹配括号

package 动态数组;
public class 匹配括号 {
    public static void main(String[] args) {
        String text ="{[<>]()}";
        //1,创建一个栈
        ArrayStack<Character> stack =new ArrayStack<>();
        //2.开始遍历text做出栈入栈的操作
        char c;
        char top;
        for(int i=0;i<text.length();i++){
              c=text.charAt(i);
              //3,如果栈为空,直接进
              if(stack.isEmpty()){
                  stack.push(c);
              }
              else{
                  top =stack.peek();
                  //top-c==-1||top-c==-2是否是一对
                  if(top-c==-1||top-c==-2){
                      //是一对,弹栈
                      stack.pop();
                  }
                  else{
                      //不是一对,进栈
                      stack.push(c);
                  }
              }
        }
        if(stack.isEmpty()){
            System.out.println("这是匹配的");
        }
        else{
            System.out.println("这不是匹配的");
        }
    }
}

中缀表达式

是一个通用的算术或者逻辑公式的表示方法,操作符是以中缀的形式处于操作数的中间(例如 3+4),与前缀表达式(例如 +3 4 )或后缀表达式(例如 3 4+)相比,中缀表达式不容易被计算机解析,但仍被许多程序语言使用,因为它符合人们的普遍用法

与前缀或后缀记法不同的是,中缀记法中括号是必须的

栈实现中缀表达式

package 动态数组;
import 动态数组.ArrayStack;
public class 中缀表达式 {
    public static void main(String[] args) {
        String expression = "(20+30/2*8/9+40-90/3*4)+40-50*6+(50*2-3)";
        //1,格式化表达式
        expression = insertBlanks(expression);
        //2.对字符串进行截取
        String [] tokens =expression.split(" ");
        //3,创建两个栈
        //数字栈
        ArrayStack<Integer> numberStack =new ArrayStack<>();
        //操作符栈
        ArrayStack<Character>  operatorStack =new ArrayStack<>();
        //4,对字符串进行foreach遍历
        for(String token:tokens){
            //如果是空字符串的话,直接跳过当前当前循环
            if(token.length()==0){
                continue;
            }
            //如果是'+'或者是'-',让操作符栈中的所有操作符进行运算
            if(token.charAt(0)=='+'||token.charAt(0)=='-'){
                while(!operatorStack.isEmpty()&&(operatorStack.peek()=='+'||operatorStack.peek()=='-'||operatorStack.peek()=='*'||operatorStack.peek()=='/')){
                    processAnOperator(numberStack,operatorStack);
                }
                operatorStack.push(token.charAt(0));
            }
            //如果是'*'或者是'/',让操作符栈中的* 和 /操作符进行运算
            else if(token.charAt(0)=='*'||token.charAt(0)=='/'){
                while(!operatorStack.isEmpty()&&(operatorStack.peek()=='*'||operatorStack.peek()=='/')){
                    processAnOperator(numberStack,operatorStack);
                }
                operatorStack.push(token.charAt(0));
            }
            //如果遍历到的是'(',就把它放到栈里
            else if(token.charAt(0)=='('){
                operatorStack.push('(');
            }
            //如果遍历到的是')',就把它放到栈里,只要栈顶元素不是'(',就一直进行运算,知道遇到'(',然后将'('弹栈即可
            else if(token.charAt(0)==')'){
                while (operatorStack.peek()!='('){
                    processAnOperator(numberStack,operatorStack);
                }
                operatorStack.pop();
            }
            else{
                //如果是数字直接进栈
                numberStack.push(new Integer(token));
            }
        }
         //两个栈还有元素没有运行完,需要继续进行运算
        while(!operatorStack.isEmpty()){
            processAnOperator(numberStack,operatorStack);
        }
        //打印最后的结果,最后的结果放到栈里
        System.out.println(numberStack.pop());
    }
     //在数字栈中弹出两个数字和在操作符栈中弹出一个字符,做运算
    private static void processAnOperator(ArrayStack<Integer> numberStack, ArrayStack<Character> operatorStack) {
        char op =operatorStack.pop();
        int num1 =numberStack.pop();
     int num2 =numberStack.pop();

    if(op=='+'){
        numberStack.push(num2+num1);
    }
    else if(op=='-'){
        numberStack.push(num2-num1);
    }
    else if(op=='*'){
        numberStack.push(num2*num1);
    }
    else if(op=='/'){
        numberStack.push(num2/num1);
    }
    }

    private static String insertBlanks(String expression) {
        StringBuilder sb = new StringBuilder();
        char c;
        //如果遇到符号,就前后加空格,如果是数字,就不加空格,直接append
        for (int i = 0; i < expression.length(); i++) {
            c = expression.charAt(i);
            if (c == '+' || c == '-' || c == '*' || c == '/'||c=='('||c==')') {
                sb.append(' ');
                sb.append(c);
                sb.append(' ');
            } else {
                //是数字
                sb.append(c);
            }
        }
        return sb.toString();
    }
}

后缀表达式

也叫逆波兰表达式,将运算符写在操作数之后

中缀转后缀的代码示例

package 动态数组;

import java.util.Arrays;
public class 中缀转后缀表达式 {
    public static void main(String[] args) {
        String infixExpression = "(20-40/2*3/8+20)/20+8/2*3-(10*4/5-6)/2";

        //中缀表达式转后缀表达式
        String suffixExpression = infixToSuffix(infixExpression);
        //打印转化后的结果
        System.out.println(suffixExpression);

    }

    private static String infixToSuffix(String infixExpression) {
          //创建一个字符栈
        ArrayStack<String> opStack =new ArrayStack<>();
        //创建一个中缀表达式的列表
        ArrayList<String> suffixList =new ArrayList<>();
        //格式化字符串
        infixExpression = insertBlanks(infixExpression);
         //切割字符串
        String [] tokens =infixExpression.split(" ");
        System.out.println(Arrays.toString(tokens));
          //遍历字符串
        for(String token:tokens){
            //过滤空字符串
            if(token.length()==0){
                continue;
            }
            if(isOperator(token)){//如果是操作符
              while(true){//这里是需要执行多次,所以要用到while(true)
                  if(opStack.isEmpty()||"(".equals(opStack.peek())){
                      opStack.push(token);
                      break;
                  }
                  if(priority(token)>priority(opStack.peek())){
                      opStack.push(token);
                      break;
                  }
                  //除了以上的情况之外,如果操作符比栈中操作符优先级小,将操作符弹栈并且添加到列表里
                  suffixList.add(opStack.pop());
              }
            }
            else if(isNumber(token)){//如果是数字
            suffixList.add(token);
            }
            else if("(".equals(token)){//如果是(
                opStack.push(token);
            }
            else if(")".equals(token)){//如果是)
               //栈顶元素是"("
                while (true){
                    if("(".equals(opStack.peek())){
                        opStack.pop();
                        break;
                    }
                    else{
                        suffixList.add(opStack.pop());
                    }
                }
            }
            else {
       throw new IllegalArgumentException("wrong identifer"+token);
            }

        }
        while (!opStack.isEmpty()){
            suffixList.add(opStack.pop());
        }
     StringBuilder sb =new StringBuilder();
        for(int i=0;i<suffixList.size();i++){
            sb.append(suffixList.get(i)+" ");
        }
        return sb.toString();
    }

    private static int priority(String token) {
     if("*".equals(token)||"/".equals(token)){
         return  1;
     }
        if("+".equals(token)||"-".equals(token)){
            return  0;
        }
        return -1;
    }

    private static boolean isNumber(String token) {
    return token.matches("\\d+");// \\d+表示匹配多个数字
    }

    private static boolean isOperator(String token) {
      return "+".equals(token)||"-".equals(token)||"*".equals(token)||"/".equals(token);
    }

    private static String insertBlanks(String infixExpression) {
    StringBuilder sb =new StringBuilder();
    //遍历表达式
        char c;
        for(int i=0;i<infixExpression.length();i++){
            c=infixExpression.charAt(i);
            if(c=='+'|| c=='-'||c=='*'||c=='/'||c=='('||c==')'){
                sb.append(' ');
                sb.append(c);
                sb.append(' ');
            }
            else{
                sb.append(c);
            }

        }
        return sb.toString();
    }

}

后缀计算器的实现

package 动态数组;

public class 后缀表达式计算器 {
    public static void main(String[] args) {
        //转换后的后缀表达式
        String expression ="20 40 2 / 3 * 8 / - 20 + 20 / 8 2 / 3 * + 10 4 * 5 / 6 - 2 / - ";
        //新建一个数字栈
        ArrayStack<Integer> stack =new ArrayStack<>();
        String [] tokens = expression.split(" ");
        for(String token:tokens){
            //如果是数字直接进
            if(isNumber(token)){
                stack.push(new Integer(token));
            }

            //如果是操作符则弹出两个数字,进行计算,然后将新的结果入栈
            else{
                processAnOperator(stack,token);
            }
        }
        //打印最后的结果
        System.out.println(stack.pop());
    }
    //运算过程
    private static void processAnOperator(ArrayStack<Integer> stack, String token) {
   int num1 = stack.pop();
   int num2 =stack.pop();
   switch (token){
       case "+":
           stack.push(num2+num1);
           break;
       case "-":
           stack.push(num2-num1);
            break;
       case "*":
           stack.push(num2*num1);
           break;
       case "/":
           stack.push(num2/num1);
           break;
   }
    }

    private static boolean isNumber(String token) {
        //表示匹配的是数字
        return token.matches("\\d+");
    }

}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值