Java数据结构之栈详解

栈的定义:

栈(stack)是一种用于存储数据的简单数据结构。栈一个有序线性表,只能在表的一端(PS:栈顶)执行插人和删除操作。最后插人的元素将被第一个删除。所以,栈也称为后进先出(Last In First Out,LIFO)或先进后出(First In Last Out,FILO)线性表。

这里写图片描述

 

Java 集合框架中的 Stack 继承自 Vector

  • 由于 Vector 有 4 个构造函数,加上 Stack 本身的一种,也就是说有 5 中创建 Stack 的方法
  • 跟 Vector 一样,它是可以由数组实现的栈

栈的几种主要基本操作:

  • void push(int data):入栈(将数据data插入到栈中)
  • int pop():出栈(删除并返回最后一个插入栈的元素)
  • int top():返回最后一个插入栈的元素,但不删除
  • int size():返回存储在栈中的元素个数
  • boolean isEmpty():返回栈是否是空栈
  • boolean isFull():返回是否是满栈
  • void Clear():清除整个栈

栈的应用:

  • 符号匹配
  • HTML和XML文件中的标签匹配(实质还是符号匹配)
  • 实现函数调用
  • 文本编辑器中的撤销
  • 网页浏览器中已访问页面的历史记录
  • 作为一个算法的辅助数据结构

栈的基本方法:

public interface Stack<E> extends Iterable<E> {
    
    //获取栈的size大小
    public int size();
    
    //判断栈是否为空
    public boolean isEmpty();
 
    //入栈 进栈一个元素 在线性表的表尾添加一个元素
    public void push(E element);

    //出栈 弹出一个元素 在线性表的表尾删除一个元素
    public E pop();

    //查看当前栈顶元素 并不是移除 查看线性表中最后一个元素
    public E peek();

    //对当前栈进行清空
    public void clear();
}

栈的几种实现方式

  1. 基于简单数组的实现方式
  2. 基于动态数组的实现方式
  3. 基于链表的实现方式
  4. 基于队列的实现方式

1.基于简单数组的实现:

        基于简单数组实现一个栈,其基本思路是这样的:从左至右向数组中添加所有的元素,并定义一个变量用来记录数组当前栈顶(top)元素的下标。当数组存满了栈元素时,执行入栈(插入元素)操作将抛出栈满异常;当对一个没有存储栈元素的数组执行出栈(删除元素)操作将抛出栈空异常,当然,这种实现方式有一个很明显的局限性。那就是:栈的最大空间必须预先声明且不能改变。试图对一个满栈执行入栈操作将会产生异常。

2.基于动态数组的实现:

        基于动态数组的实现一个栈,其基本思路跟上面类似。不同的是,这种方式下当数组中存储的元素达到一定量时(如:数组空间的0.75或者整个数组空间),这时我们通常会选择新建一个比原数组空间大一倍的新数组,然后将原数组按照原来的顺序复制进去,接着便可以继续进行入栈操作了。

import p1.Stack;(上方的Stack包)

import java.util.Iterator;

public class ArrayStack<E> implements Stack<E> {
    
    //定义私有变量List
    private ArrayList<E> list;
    
    //默认构造
    public ArrayStack() {
        list = new ArrayList<>();
    }
    //自己定义数组长度
    public ArrayStack(int capacity) {
        list = new ArrayList<>(capacity);
    }
    
    //size实现
    @Override
    public int size() {
        return list.size();
    }
    //判空实现
    @Override
    public boolean isEmpty() {
        return list.isEmpty();
    }
    //push方法
    @Override
    public void push(E element) {
        list.add(element);
    }
    //pop方法实现
    @Override
    public E pop() {
        return list.remove(list.size() - 1);
    }
    //peek实现
    @Override
    public E peek() {
        return list.get(list.size() - 1);
    }
    //clear方法
    @Override
    public void clear() {
        list.clear();
    }
    //迭代方法
    @Override
    public Iterator<E> iterator() {
        return list.iterator();
    }
    //toString方法实现
    @Override
    public String toString() {
        return list.toString();
    }
    //继承Object equals方法
    @Override
    public boolean equals(Object o) {
        if (o == null) {
            return false;
        }
        if (this == o) {
            return true;
        }
        if (o instanceof ArrayStack) {
            ArrayStack other = (ArrayStack) o;
            return this.list.equals(other.list);
        }
        return false;
    }
}

3.基于链表的实现:

        基于链表实现一个栈,其基本思路是这样的:通过在链表的表头插入元素的方式来实现push操作;通过删除链表的表头节点的方式来实现pop操作.

public class SinglyNode<K extends Object> {
    private K data; // 数据
    private SinglyNode<K> next; // 该节点的下个节点
 
    public SinglyNode(K data) {
        this.data = data;
    }
 
    public SinglyNode(K data, SinglyNode<K> next) {
        this.data = data;
        this.next = next;
    }
 
    public K getData() {
        return data;
    }
 
    public void setData(K data) {
        this.data = data;
    }
 
    public SinglyNode<K> getNext() {
        return next;
    }
 
    public void setNext(SinglyNode<K> next) {
        this.next = next;
    }
 
    @Override
    public String toString() {
        return "SinglyNode [data=" + data + "]";
    }
 
}
public class LinkStack<K extends Object> implements Stack<K> {
 
    private SinglyNode<K> headNode;
    //是否为满栈
    public boolean isFull() {
        return false;
    }
    //是否为空
    public boolean isEmpty(){
        return headNode == null ? true : false;
    }
    
    
    //入栈
    public void push(K data){
        if(headNode == null){
            headNode = new SinglyNode<K>(data);
        }else{
            SinglyNode<K> newNode = new SinglyNode<K>(data);
            newNode.setNext(headNode);
            headNode = newNode;
        }
    }
    
    //出栈
    public K pop(){
        if(headNode == null){
            throw new EmptyStackException();
        }else{
            K data = headNode.getData();
            headNode = headNode.getNext();
            return data;
        }
    }
    
    //返回栈顶元素
    public K top(){
        if(headNode == null){
            throw new EmptyStackException();
        }else{
            return headNode.getData();
        }
    }
    
    //返回栈中元素个数
    public int size(){
        if(headNode == null){
            return 0;
        }else{
            int length = 0;
            SinglyNode<K> currentNode = headNode;
            while (currentNode != null) {
                length++;
                currentNode = currentNode.getNext();
            }
            return length;
        }
    }
    
    //清空栈
    public void ClearStack(){
        headNode = null;
    }
 
   //遍历栈从前往后
    @Override
    public void print() {
        SinglyNode<K> tmpNode = headNode;
        printFromEnd(tmpNode);
    }
    
    //遍历栈从后往前
    public void printFromEnd(SinglyNode<K> headNode){
        if(headNode != null){
            if(headNode.getNext() != null){
                printFromEnd(headNode.getNext());
            }
            
            System.out.print(headNode.getData() + " ");
        }
    }
 
}

 基于数组实现和基于链表实现的比较

(1)基于数组实现的栈:

  • 各个操作都是常数时间开销
  • 每隔一段时间进行的倍增操作的时间开销较大

(2)基于链表实现的栈:

  • 栈规模的增加和减小都很容易
  • 各个操作都是常数时间开销
  • 每个操作都需要使用额外的空间和时间开销来处理指针

4.基于队列实现栈:

import java.util.Iterator;

//队列实现栈
public class QueueToStack {
    public static void main(String[] args) {
        StackImplByQueue<Integer> stack = new StackImplByQueue<>();
        System.out.println(stack);
        for (int i = 1; i <= 5; i++) {
            stack.push(i); //队列A
        }
        System.out.println(stack.toString());
        System.out.println(stack.pop());
        System.out.println(stack);  //队列B

    }
}

class StackImplByQueue<E> implements Stack<E> { //上方的栈调用
    private ArrayQueue<E> queueA;
    private ArrayQueue<E> queueB;

    public StackImplByQueue() {
        queueA = new ArrayQueue<>();
        queueB = new ArrayQueue<>();
    }

    @Override
    public int size() {
        if (queueA.isEmpty() && queueB.isEmpty()) {
            return 0;
        } else if (!queueA.isEmpty()) {
            return queueA.size();
        } else {
            return queueB.size();
        }
    }

    @Override
    public boolean isEmpty() {
        return queueA.isEmpty() && queueB.isEmpty();
    }

    @Override
    public void push(E element) {
        if (queueA.isEmpty() && queueB.isEmpty()) {
            queueA.offer(element);
        } else if (!queueA.isEmpty()) {
            queueA.offer(element);
        } else {
            queueB.offer(element);
        }
    }

    @Override
    public E pop() {
        if (isEmpty()) {
            return null;
        }
        E ret = null;
        if (!queueA.isEmpty()) {
            while (queueA.size() != 1) {
                queueB.offer(queueA.poll());
            }
            ret = queueA.poll();
        } else {
            while (queueB.size() != 1) {
                queueA.offer(queueB.poll());
            }
            ret = queueB.poll();
        }
        return ret;
    }

    @Override
    public E peek() {
        if (isEmpty()) {
            return null;
        }
        E ret = null;
        if (!queueA.isEmpty()) {
            while (queueA.size() != 1) {
                queueB.offer(queueA.poll());
            }
            ret = queueA.poll();
            queueB.offer(ret);
        } else {
            while (queueB.size() != 1) {
                queueA.offer(queueB.poll());
            }
            ret = queueB.poll();
            queueA.offer(ret);
        }
        return ret;
    }

    @Override
    public void clear() {
        queueA.clear();
        queueB.clear();
    }

    @Override
    public Iterator<E> iterator() {
        if (isEmpty()) {
            return queueA.iterator();
        } else if (!queueA.isEmpty()) {
            return queueA.iterator();
        } else {
            return queueB.iterator();
        }
    }
    @Override
    public String toString() {
        if (isEmpty()) {
            return "[]";
        } else if (!queueA.isEmpty()) {
            return queueA.toString();
        } else {
            return queueB.toString();
        }
    }

}

Java 集合框架中的 Stack 具有以下特点:

  • 继承自 Vector
  • 有 5 种创建 Stack 的方法
  • 采用数组实现
  • 除了 push(),剩下的方法都是同步的。

双端栈:

        双端栈定义:

                是指一个线性表的两端当做栈底,分别进行入栈和出栈操作,主要利用了栈:栈底不变,栈顶变化的特征;

        

        双端栈是线性表的一种,更是栈的一个特殊分类,可用借用动态数组+栈的组合实现。

 

 双端栈实现方法以及基本方法:

import java.util.Iterator;
    //双端栈
public class ArrayDoubleEndStack<E> implements Iterable<E> {
    //左端栈的栈顶
    private int ltop;
    //右端栈的栈顶
    private int rtop;
    //存储元素的容器
    private E[] data;
    //数组容器的默认容量
    private static int DEFAULT_CAPACITY = 10;
    //构造
    public ArrayDoubleEndStack() {
        data = (E[]) new Object[DEFAULT_CAPACITY];
        ltop = -1;
        rtop = data.length;
    }
    //左入栈
    public void pushLeft(E element) {
        if (ltop + 1 == rtop) {
            resize(data.length * 2);
        }
        data[++ltop] = element;
    }
    //右入栈
    public void pushRight(E element) {
        if (ltop + 1 == rtop) {
            resize(data.length * 2);
        }
        data[--rtop] = element;
    }
    //扩容
    private void resize(int newLen) {
        E[] newData = (E[]) new Object[newLen];
        //复制左端栈的元素
        for (int i = 0; i <= ltop; i++) {
            newData[i] = data[i];
        }
        //复制右端栈的元素
        int index = rtop;
        for (int i = newLen - sizeRight(); i < newLen; i++) {
            newData[i] = data[index++];
        }
        rtop = newLen - sizeRight();
        data = newData;
    }
    //左出栈
    public E popLeft() {
        if (isLeftEmpty()) {
            throw new IllegalArgumentException("left stack is null");
        }
        E ret = data[ltop--];
        if (sizeLeft() + sizeRight() <= data.length / 4 && data.length > DEFAULT_CAPACITY) {
            resize(data.length / 2);
        }
        return ret;
    }
    //右出栈
    public E popRight() {
        if (isRightEmpty()) {
            throw new IllegalArgumentException("right stack is null");
        }
        E ret = data[rtop++];
        if (sizeLeft() + sizeRight() <= data.length / 4 && data.length > DEFAULT_CAPACITY) {
            resize(data.length / 2);
        }
        return ret;
    }
    //获取左栈顶
    public E peekLeft() {
        if (isLeftEmpty()) {
            throw new IllegalArgumentException("left stack is null");
        }
        return data[ltop];
    }
    //获取右栈顶
    public E peekRight() {
        if (isRightEmpty()) {
            throw new IllegalArgumentException("right stack is null");
        }
        return data[rtop];
    }
    
    //判断是否左边为空
    public boolean isLeftEmpty() {
        return ltop == -1;
    }
    //判断是否右边为空
    public boolean isRightEmpty() {
        return rtop == data.length;
    }
    //通过左指针获取长度
    public int sizeLeft() {
        return ltop + 1;
    }
    //通过右指针获取长度
    public int sizeRigh() {
        return data.length - rtop;
    }
    //重写toString方法
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append('[');
        if (isLeftEmpty() && isRightEmpty()) {
            sb.append(']');
            return sb.toString();
        }
        //先左边
        for (int i = 0; i <= ltop; i++) {
            sb.append(data[i]);
            if (i == ltop && isRightEmpty()) {
                sb.append(']');
                return sb.toString();
            } else {
                sb.append(',');
            }
        }
        //后右边
        for (int i = rtop; i < data.length; i++) {
            sb.append(data[i]);
            if (i == data.length - 1) {
                sb.append(']');
            } else {
                sb.append(',');
            }
        }
        return sb.toString();
    }
    //迭代器
    @Override
    public Iterator<E> iterator() {
        return new ArrayDoubleEndStackIterator();
    }

    class ArrayDoubleEndStackIterator implements Iterator<E> {
        private ArrayList<E> list;
        private Iterator<E> it;
        public ArrayDoubleEndStackIterator() {
            list = new ArrayList<>();
            for (int i = 0; i <= ltop; i++) {
                list.add(data[i]);
            }
            for (int i = rtop; i < data.length; i++) {
                list.add(data[i]);
            }
            it = list.iterator();
        }

        @Override
        public boolean hasNext() {
            return it.hasNext();
        }

        @Override
        public E next() {
            return it.next();
        }
    }
}

双端栈的扩容与缩容问题;

        双端栈A中有下标0-5的6个元素,对其进行扩容;

         对其扩容时候,先考虑左边,从原来双端栈A的左边原封不动直接进入双端栈B,此时与双端栈A的左指针相同,皆为下标2,此时双端栈B的前3个元素不动,下标为【0,ltop】。

        其次考虑右边的情况,通过观察,发现index为5的元素对应到11,所以即为newLen-1,而先前的rtop从双端栈A的3变到了双端栈B的9,可以观察到9 = 12 - 3;此时rtop =  newLen -  size(1)

这时候原先双端栈A的右边完全到了双端栈B的左边,完成了对双端栈A的扩容问题。

关于栈的习题应用:

1.关于题解回文数;

        给定一个字符串,判断是否该字符串是否是回文字符串,即"aba" 则为一个满足回文的条件;

public class JudgingPalindrome {
    public static void main(String[] args) {
        solution01();
        System.out.println(solution02());
    }
    //通过栈的思想
    private static void solution01() {
        String text = "上海自来水来自海上"; 
        ArrayStack<Character> stack = new ArrayStack<>();
           //遍历栈中元素
         for (int i = 0; i < text.length(); i++) {
            //对于栈中元素是奇是偶进行判断
            if (text.length() % 2 == 1 && i == text.length() / 2) {
                continue;
            }
            char c = text.charAt(i);
            //栈空进栈,相同时候元素弹出,不同时候进栈,判断最后是否栈为空,为空则回文
            if (stack.isEmpty()) {
               stack.push(c);
            } else {
                if (c != stack.peek()) {
                    stack.push(c);
                } else {
                    stack.pop();
                }
            }
        }
        System.out.println(stack.isEmpty());
    }
        //通过双指针的思想
        private static boolean solution02() {
        String text = "上海自来水来自海上";
        //头指针
        int i = 0;
        //尾指针
        int j = text.length() - 1;
        //循环条件,头尾同时进行,首位匹配下一位,不同则返回false;
        while (true) {
            if (text.charAt(i) == text.charAt(j)) {
                i++;
                j--;
            } else {
                return false;
            }
            //尾指针要小于等于头指针
            if (j <= i) {
                return true;
            }
        }
    }
}

2.关于括号匹配问题

        给定一些列括号‘(‘ ,’)’,‘【‘,’】’等,判断给定的括号串,是否完全匹配。如:“({()()})”;


//括号匹配
import java.util.HashMap;

public class MatchBracket {
    public static void main(String[] args) {
        solution01();
        solution02();
    }

    //通过栈的思想解决
    private static void solution01() {
        String str = "{()[[()]]<>{}()<>}()";
        ArrayStack<Character> stack = new ArrayStack<>();
     
           //循环该数组下标,栈为空进栈
            for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (stack.isEmpty()) {
                stack.push(c);
            } else {
               //当前栈顶
                char top = stack.peek();
                //通过ascll码匹配当满足条件时候,弹栈,即完成匹配
                if (top - c == -1 || top - c == -2) {
                    stack.pop();
                } else {
                    stack.push(c);
                }
            }
        }
        //当stack为空时候说明括号完全匹配
        System.out.println(stack.isEmpty());
    }
        
        //通过HashMap实现
        private static void solution02() {
        String str = "{()[[()]]<{()>}()";
        //给定hashmap的键值对应关系
        HashMap<Character,Character> map = new HashMap<>();
        map.put('[',']');
        map.put('<','>');
        map.put('(',')');
        map.put('{','}');
        ArrayStack<Character> stack = new ArrayStack<>();
        //遍历和法1相同
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (stack.isEmpty()) {
                stack.push(c);
            } else {
                char top = stack.peek();
                //contains保证键值关系,包含时候,看c是否满足关系,满足时候弹栈,不满足继续入栈
                if (map.containsKey(top) && c == map.get(']')) {
                    stack.pop();
                } else {
                    stack.push(c);
                }
            }
        }
        System.out.println(stack.isEmpty());
    }
}

3.简单计算器的实现

        给定(),+ - */四则运算,做出来一个简单的计算器 如(10+20/2*3)/2+8 = 28

        3.1中缀表达式计算器

//中缀表达式计算器
public class InfixCalculator {
    public static void main(String[] args) {
        String expression = "(10+20/2*3)/2+8";
        try {
            int result = evaluateExpression(expression);
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Wrong expression :" + expression);
        }
    }

    private static int evaluateExpression(String expression) {
        //需要两个辅助栈
        ArrayStack<Character> operatorStack = new ArrayStack<>();
        ArrayStack<Integer> numberStack = new ArrayStack<>();

        //格式化表达式
        expression = insertBlanks(expression);
        String[] tokens = expression.split(" ");
        for (String token : tokens) {   //token == tokens[i]
            //过滤空串
            if (token.length() == 0) {
                continue;
                //遍历到 + - 号
            } else if (token.equals("+") || token.equals("-")) {
                while (!operatorStack.isEmpty() && (operatorStack.peek() == '+' || operatorStack.peek() == '-' || operatorStack.peek() == '*' || operatorStack.peek() == '/')) {
                    //如果之前是别的+ - * / 则需要弹栈 并计算
                    processAnOperator(numberStack, operatorStack);
                }
                //如果操作符栈为空 或者 不为空但栈顶为(
                operatorStack.push(token.charAt(0));

                //遍历到 * / 号
            } else if (token.equals("*") || token.equals("/")) {
                while (!operatorStack.isEmpty() && (operatorStack.peek() == '*' || operatorStack.peek() == '/')) {
                    //如果之前是别的* / 则需要弹栈 并计算
                    processAnOperator(numberStack, operatorStack);
                }
                //如果操作符栈为空 或者 不为空但栈顶为(
                operatorStack.push(token.charAt(0));

                //遍历到 (
            } else if (token.equals("(")) {
                operatorStack.push(token.charAt(0));

                //遍历到 )
            } else if (token.equals(")")) {
                //只要操作符栈的栈顶不是左括号( 就挨个弹栈计算即可
                while (operatorStack.peek() != '(') {
                    processAnOperator(numberStack, operatorStack);
                }
                //最后 清掉左括号
                operatorStack.pop();

                //遍历到数字
            } else {
                numberStack.push(new Integer(token));
            }
        }

        //处理最后面的操作符
        while (!operatorStack.isEmpty()) {
            processAnOperator(numberStack, operatorStack);
        }
        return numberStack.pop();
    }

    //操作符栈弹栈一个元素 数字栈弹栈两个数字 进行计算 并将新的结果进栈到数字栈
    private static void processAnOperator(ArrayStack<Integer> numberStack, ArrayStack<Character> operatorStack) {
        char op = operatorStack.pop();
        int num1 = numberStack.pop();
        int num2 = numberStack.pop();
        //num2 op num1
        if (op == '+') {
            numberStack.push(num2 + num1);
        } else if (op == '-') {
            numberStack.push(num2 - num1);
        } else if (op == '*') {
            numberStack.push(num2 * num1);
        } else {
            numberStack.push(num2 / num1);
        }
    }

    //对原表达式进行格式化处理 给所有的非数字字符两边添加空格
    private static String insertBlanks(String expression) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < expression.length(); i++) {
            char 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();
    }
}

        3.2后缀表达式计算器

        

//后缀表达式的计算器
public class SuffixCalculator {
    public static void main(String[] args) {
        String infixExpression = "(10+20/2*3)/2+8";
        String suffixExpression = InfixToSuffix.infixToSuffix(infixExpression);
        int result = evaluateSuffix(suffixExpression);
        System.out.println(result);
    }

    private static int evaluateSuffix(String expression) {
        ArrayStack<Integer> stack = new ArrayStack<>();
        String[] tokens = expression.split(" ");
        for (String token : tokens) {
            if (token.length() == 0) {
                continue;
            }
            if (isNumber(token)) {
                stack.push(new Integer(token));
            } else {
                processAnOperator(stack,token);
            }
        }
        return stack.pop();
    }

    private static void processAnOperator(ArrayStack<Integer> stack, String token) {
        int num1 = stack.pop();
        int num2 = stack.pop();
        if (token.equals("+")) {
            stack.push(num2 + num1);
        } else if (token.equals("-")) {
            stack.push(num2 - num1);
        } else if (token.equals("*")) {
            stack.push(num2 * num1);
        } else if (token.equals("/")) {
            stack.push(num2 / num1);
        }
    }

    private static boolean isNumber(String token) {
        return token.matches("\\d+");
    }
}

        3.3中缀转换后缀

        

//中缀表达式转后缀表达式
public class InfixToSuffix {
    public static void main(String[] args) {
        String expression = "(10+20/2*3)/2+8";
        expression = infixToSuffix(expression);
        System.out.println(expression);
    }
    private static String infixToSuffix(String expression) {
        //操作符的栈
        ArrayStack<String> opStack = new ArrayStack<>();
        //后缀表达式的线性表
        ArrayList<String> suffixList = new ArrayList<>();
        //格式化表达式
        expression = insertBlanks(expression);
        String[] tokens = expression.split(" ");
        for (String token : tokens) {
            //过滤空串
            if (token.length() == 0) {
                continue;
            }
            //判断操作符+ - * /
            if (isOperator(token)) {
                /*
                什么时候操作符进栈?
                1.如果栈为空
                2.如果栈顶是 (
                3.如果栈顶是操作符,且优先级比当前token小
                什么时候需要将栈顶操作符出栈?
                1.栈顶操作符的优先级 >= 当前token
                */
                while (true) {
                    if (opStack.isEmpty() || opStack.peek().equals("(") || priority(opStack.peek()) < priority(token)) {
                        opStack.push(token);
                        break;
                    }
                    suffixList.add(opStack.pop());
                }
            } else if (token.equals("(")) {
                opStack.push(token);
            } else if (token.equals(")")) {
                while (!opStack.peek().equals("(")) {
                    suffixList.add(opStack.pop());
                }
                opStack.pop();
            } else if (isNumber(token)) {
                suffixList.add(token);
            } else {
                throw new IllegalArgumentException("wrong char :" + expression);
            }
        }
        while (!opStack.isEmpty()) {
            suffixList.add(opStack.pop());
        }
        //将数字元素和操作符元素进行拼接
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < suffixList.size(); i++) {
            sb.append(suffixList.get(i));
            sb.append(' ');
        }
        return sb.toString();
    }

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

    private static boolean isNumber(String token) {
        return token.matches("\\d+");
    }

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

    //对原表达式进行格式化处理 给所有的非数字字符两边添加空格
    private static String insertBlanks(String expression) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < expression.length(); i++) {
            char 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();
    }
}

  • 17
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
链表是一种常见的数据结构,用于存储一系列的元素。在Java,链表可以使用LinkedList类来实现。下面是关于Java链表的详细解释: 链表由节点(Node)组成,每个节点包含两部分:数据域(存储元素的值)和指针域(指向下一个节点的指针)。链表的头节点是链表的起始点,尾节点是链表的结束点。 Java的LinkedList类实现了List接口和Deque接口,因此可以用作列表和双端队列。LinkedList在内存以链式结构存储元素,相邻元素通过节点的指针连接。 与数组相比,链表的一个优势是可以快速地插入和删除元素。由于链表的元素在内存不连续存储,所以插入和删除只需要改变指针的指向,而不需要移动其他元素。然而,链表的一个劣势是访问特定索引的元素比较慢,因为需要从头节点开始遍历链表。 下面是一些常用的操作示例: 1. 创建一个空链表: LinkedList<String> list = new LinkedList<>(); 2. 在链表末尾添加元素: list.add("A"); list.add("B"); list.add("C"); 3. 在指定位置插入元素: list.add(1, "D"); // 在索引为1的位置插入元素D 4. 获取链表的大小: int size = list.size(); 5. 获取指定索引位置的元素: String element = list.get(2); // 获取索引为2的元素 6. 修改指定索引位置的元素: list.set(0, "E"); // 将索引为0的元素修改为E 7. 删除指定索引位置的元素: list.remove(1); // 删除索引为1的元素 8. 遍历链表: for (String element : list) { System.out.println(element); } 需要注意的是,LinkedList类不是线程安全的,如果在多线程环境使用链表,需要进行适当的同步处理。此外,由于链表的元素不是连续存储,所以对于大量元素的访问和操作,可能会导致性能下降。在这种情况下,可以考虑使用ArrayList或其他更适合的数据结构

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值