当前位置:   article > 正文

Java数据结构之栈详解_java中的栈

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

栈的基本方法:

  1. public interface Stack<E> extends Iterable<E> {
  2. //获取栈的size大小
  3. public int size();
  4. //判断栈是否为空
  5. public boolean isEmpty();
  6. //入栈 进栈一个元素 在线性表的表尾添加一个元素
  7. public void push(E element);
  8. //出栈 弹出一个元素 在线性表的表尾删除一个元素
  9. public E pop();
  10. //查看当前栈顶元素 并不是移除 查看线性表中最后一个元素
  11. public E peek();
  12. //对当前栈进行清空
  13. public void clear();
  14. }

栈的几种实现方式

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

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

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

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

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

  1. import p1.Stack;(上方的Stack包)
  2. import java.util.Iterator;
  3. public class ArrayStack<E> implements Stack<E> {
  4. //定义私有变量List
  5. private ArrayList<E> list;
  6. //默认构造
  7. public ArrayStack() {
  8. list = new ArrayList<>();
  9. }
  10. //自己定义数组长度
  11. public ArrayStack(int capacity) {
  12. list = new ArrayList<>(capacity);
  13. }
  14. //size实现
  15. @Override
  16. public int size() {
  17. return list.size();
  18. }
  19. //判空实现
  20. @Override
  21. public boolean isEmpty() {
  22. return list.isEmpty();
  23. }
  24. //push方法
  25. @Override
  26. public void push(E element) {
  27. list.add(element);
  28. }
  29. //pop方法实现
  30. @Override
  31. public E pop() {
  32. return list.remove(list.size() - 1);
  33. }
  34. //peek实现
  35. @Override
  36. public E peek() {
  37. return list.get(list.size() - 1);
  38. }
  39. //clear方法
  40. @Override
  41. public void clear() {
  42. list.clear();
  43. }
  44. //迭代方法
  45. @Override
  46. public Iterator<E> iterator() {
  47. return list.iterator();
  48. }
  49. //toString方法实现
  50. @Override
  51. public String toString() {
  52. return list.toString();
  53. }
  54. //继承Object equals方法
  55. @Override
  56. public boolean equals(Object o) {
  57. if (o == null) {
  58. return false;
  59. }
  60. if (this == o) {
  61. return true;
  62. }
  63. if (o instanceof ArrayStack) {
  64. ArrayStack other = (ArrayStack) o;
  65. return this.list.equals(other.list);
  66. }
  67. return false;
  68. }
  69. }

3.基于链表的实现:

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

  1. public class SinglyNode<K extends Object> {
  2. private K data; // 数据
  3. private SinglyNode<K> next; // 该节点的下个节点
  4. public SinglyNode(K data) {
  5. this.data = data;
  6. }
  7. public SinglyNode(K data, SinglyNode<K> next) {
  8. this.data = data;
  9. this.next = next;
  10. }
  11. public K getData() {
  12. return data;
  13. }
  14. public void setData(K data) {
  15. this.data = data;
  16. }
  17. public SinglyNode<K> getNext() {
  18. return next;
  19. }
  20. public void setNext(SinglyNode<K> next) {
  21. this.next = next;
  22. }
  23. @Override
  24. public String toString() {
  25. return "SinglyNode [data=" + data + "]";
  26. }
  27. }
  1. public class LinkStack<K extends Object> implements Stack<K> {
  2. private SinglyNode<K> headNode;
  3. //是否为满栈
  4. public boolean isFull() {
  5. return false;
  6. }
  7. //是否为空
  8. public boolean isEmpty(){
  9. return headNode == null ? true : false;
  10. }
  11. //入栈
  12. public void push(K data){
  13. if(headNode == null){
  14. headNode = new SinglyNode<K>(data);
  15. }else{
  16. SinglyNode<K> newNode = new SinglyNode<K>(data);
  17. newNode.setNext(headNode);
  18. headNode = newNode;
  19. }
  20. }
  21. //出栈
  22. public K pop(){
  23. if(headNode == null){
  24. throw new EmptyStackException();
  25. }else{
  26. K data = headNode.getData();
  27. headNode = headNode.getNext();
  28. return data;
  29. }
  30. }
  31. //返回栈顶元素
  32. public K top(){
  33. if(headNode == null){
  34. throw new EmptyStackException();
  35. }else{
  36. return headNode.getData();
  37. }
  38. }
  39. //返回栈中元素个数
  40. public int size(){
  41. if(headNode == null){
  42. return 0;
  43. }else{
  44. int length = 0;
  45. SinglyNode<K> currentNode = headNode;
  46. while (currentNode != null) {
  47. length++;
  48. currentNode = currentNode.getNext();
  49. }
  50. return length;
  51. }
  52. }
  53. //清空栈
  54. public void ClearStack(){
  55. headNode = null;
  56. }
  57. //遍历栈从前往后
  58. @Override
  59. public void print() {
  60. SinglyNode<K> tmpNode = headNode;
  61. printFromEnd(tmpNode);
  62. }
  63. //遍历栈从后往前
  64. public void printFromEnd(SinglyNode<K> headNode){
  65. if(headNode != null){
  66. if(headNode.getNext() != null){
  67. printFromEnd(headNode.getNext());
  68. }
  69. System.out.print(headNode.getData() + " ");
  70. }
  71. }
  72. }

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

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

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

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

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

4.基于队列实现栈:

  1. import java.util.Iterator;
  2. //队列实现栈
  3. public class QueueToStack {
  4. public static void main(String[] args) {
  5. StackImplByQueue<Integer> stack = new StackImplByQueue<>();
  6. System.out.println(stack);
  7. for (int i = 1; i <= 5; i++) {
  8. stack.push(i); //队列A
  9. }
  10. System.out.println(stack.toString());
  11. System.out.println(stack.pop());
  12. System.out.println(stack); //队列B
  13. }
  14. }
  15. class StackImplByQueue<E> implements Stack<E> { //上方的栈调用
  16. private ArrayQueue<E> queueA;
  17. private ArrayQueue<E> queueB;
  18. public StackImplByQueue() {
  19. queueA = new ArrayQueue<>();
  20. queueB = new ArrayQueue<>();
  21. }
  22. @Override
  23. public int size() {
  24. if (queueA.isEmpty() && queueB.isEmpty()) {
  25. return 0;
  26. } else if (!queueA.isEmpty()) {
  27. return queueA.size();
  28. } else {
  29. return queueB.size();
  30. }
  31. }
  32. @Override
  33. public boolean isEmpty() {
  34. return queueA.isEmpty() && queueB.isEmpty();
  35. }
  36. @Override
  37. public void push(E element) {
  38. if (queueA.isEmpty() && queueB.isEmpty()) {
  39. queueA.offer(element);
  40. } else if (!queueA.isEmpty()) {
  41. queueA.offer(element);
  42. } else {
  43. queueB.offer(element);
  44. }
  45. }
  46. @Override
  47. public E pop() {
  48. if (isEmpty()) {
  49. return null;
  50. }
  51. E ret = null;
  52. if (!queueA.isEmpty()) {
  53. while (queueA.size() != 1) {
  54. queueB.offer(queueA.poll());
  55. }
  56. ret = queueA.poll();
  57. } else {
  58. while (queueB.size() != 1) {
  59. queueA.offer(queueB.poll());
  60. }
  61. ret = queueB.poll();
  62. }
  63. return ret;
  64. }
  65. @Override
  66. public E peek() {
  67. if (isEmpty()) {
  68. return null;
  69. }
  70. E ret = null;
  71. if (!queueA.isEmpty()) {
  72. while (queueA.size() != 1) {
  73. queueB.offer(queueA.poll());
  74. }
  75. ret = queueA.poll();
  76. queueB.offer(ret);
  77. } else {
  78. while (queueB.size() != 1) {
  79. queueA.offer(queueB.poll());
  80. }
  81. ret = queueB.poll();
  82. queueA.offer(ret);
  83. }
  84. return ret;
  85. }
  86. @Override
  87. public void clear() {
  88. queueA.clear();
  89. queueB.clear();
  90. }
  91. @Override
  92. public Iterator<E> iterator() {
  93. if (isEmpty()) {
  94. return queueA.iterator();
  95. } else if (!queueA.isEmpty()) {
  96. return queueA.iterator();
  97. } else {
  98. return queueB.iterator();
  99. }
  100. }
  101. @Override
  102. public String toString() {
  103. if (isEmpty()) {
  104. return "[]";
  105. } else if (!queueA.isEmpty()) {
  106. return queueA.toString();
  107. } else {
  108. return queueB.toString();
  109. }
  110. }
  111. }

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

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

双端栈:

        双端栈定义:

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

        

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

 

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

  1. import java.util.Iterator;
  2. //双端栈
  3. public class ArrayDoubleEndStack<E> implements Iterable<E> {
  4. //左端栈的栈顶
  5. private int ltop;
  6. //右端栈的栈顶
  7. private int rtop;
  8. //存储元素的容器
  9. private E[] data;
  10. //数组容器的默认容量
  11. private static int DEFAULT_CAPACITY = 10;
  12. //构造
  13. public ArrayDoubleEndStack() {
  14. data = (E[]) new Object[DEFAULT_CAPACITY];
  15. ltop = -1;
  16. rtop = data.length;
  17. }
  18. //左入栈
  19. public void pushLeft(E element) {
  20. if (ltop + 1 == rtop) {
  21. resize(data.length * 2);
  22. }
  23. data[++ltop] = element;
  24. }
  25. //右入栈
  26. public void pushRight(E element) {
  27. if (ltop + 1 == rtop) {
  28. resize(data.length * 2);
  29. }
  30. data[--rtop] = element;
  31. }
  32. //扩容
  33. private void resize(int newLen) {
  34. E[] newData = (E[]) new Object[newLen];
  35. //复制左端栈的元素
  36. for (int i = 0; i <= ltop; i++) {
  37. newData[i] = data[i];
  38. }
  39. //复制右端栈的元素
  40. int index = rtop;
  41. for (int i = newLen - sizeRight(); i < newLen; i++) {
  42. newData[i] = data[index++];
  43. }
  44. rtop = newLen - sizeRight();
  45. data = newData;
  46. }
  47. //左出栈
  48. public E popLeft() {
  49. if (isLeftEmpty()) {
  50. throw new IllegalArgumentException("left stack is null");
  51. }
  52. E ret = data[ltop--];
  53. if (sizeLeft() + sizeRight() <= data.length / 4 && data.length > DEFAULT_CAPACITY) {
  54. resize(data.length / 2);
  55. }
  56. return ret;
  57. }
  58. //右出栈
  59. public E popRight() {
  60. if (isRightEmpty()) {
  61. throw new IllegalArgumentException("right stack is null");
  62. }
  63. E ret = data[rtop++];
  64. if (sizeLeft() + sizeRight() <= data.length / 4 && data.length > DEFAULT_CAPACITY) {
  65. resize(data.length / 2);
  66. }
  67. return ret;
  68. }
  69. //获取左栈顶
  70. public E peekLeft() {
  71. if (isLeftEmpty()) {
  72. throw new IllegalArgumentException("left stack is null");
  73. }
  74. return data[ltop];
  75. }
  76. //获取右栈顶
  77. public E peekRight() {
  78. if (isRightEmpty()) {
  79. throw new IllegalArgumentException("right stack is null");
  80. }
  81. return data[rtop];
  82. }
  83. //判断是否左边为空
  84. public boolean isLeftEmpty() {
  85. return ltop == -1;
  86. }
  87. //判断是否右边为空
  88. public boolean isRightEmpty() {
  89. return rtop == data.length;
  90. }
  91. //通过左指针获取长度
  92. public int sizeLeft() {
  93. return ltop + 1;
  94. }
  95. //通过右指针获取长度
  96. public int sizeRigh() {
  97. return data.length - rtop;
  98. }
  99. //重写toString方法
  100. @Override
  101. public String toString() {
  102. StringBuilder sb = new StringBuilder();
  103. sb.append('[');
  104. if (isLeftEmpty() && isRightEmpty()) {
  105. sb.append(']');
  106. return sb.toString();
  107. }
  108. //先左边
  109. for (int i = 0; i <= ltop; i++) {
  110. sb.append(data[i]);
  111. if (i == ltop && isRightEmpty()) {
  112. sb.append(']');
  113. return sb.toString();
  114. } else {
  115. sb.append(',');
  116. }
  117. }
  118. //后右边
  119. for (int i = rtop; i < data.length; i++) {
  120. sb.append(data[i]);
  121. if (i == data.length - 1) {
  122. sb.append(']');
  123. } else {
  124. sb.append(',');
  125. }
  126. }
  127. return sb.toString();
  128. }
  129. //迭代器
  130. @Override
  131. public Iterator<E> iterator() {
  132. return new ArrayDoubleEndStackIterator();
  133. }
  134. class ArrayDoubleEndStackIterator implements Iterator<E> {
  135. private ArrayList<E> list;
  136. private Iterator<E> it;
  137. public ArrayDoubleEndStackIterator() {
  138. list = new ArrayList<>();
  139. for (int i = 0; i <= ltop; i++) {
  140. list.add(data[i]);
  141. }
  142. for (int i = rtop; i < data.length; i++) {
  143. list.add(data[i]);
  144. }
  145. it = list.iterator();
  146. }
  147. @Override
  148. public boolean hasNext() {
  149. return it.hasNext();
  150. }
  151. @Override
  152. public E next() {
  153. return it.next();
  154. }
  155. }
  156. }

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

        双端栈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" 则为一个满足回文的条件;

  1. public class JudgingPalindrome {
  2. public static void main(String[] args) {
  3. solution01();
  4. System.out.println(solution02());
  5. }
  6. //通过栈的思想
  7. private static void solution01() {
  8. String text = "上海自来水来自海上";
  9. ArrayStack<Character> stack = new ArrayStack<>();
  10. //遍历栈中元素
  11. for (int i = 0; i < text.length(); i++) {
  12. //对于栈中元素是奇是偶进行判断
  13. if (text.length() % 2 == 1 && i == text.length() / 2) {
  14. continue;
  15. }
  16. char c = text.charAt(i);
  17. //栈空进栈,相同时候元素弹出,不同时候进栈,判断最后是否栈为空,为空则回文
  18. if (stack.isEmpty()) {
  19. stack.push(c);
  20. } else {
  21. if (c != stack.peek()) {
  22. stack.push(c);
  23. } else {
  24. stack.pop();
  25. }
  26. }
  27. }
  28. System.out.println(stack.isEmpty());
  29. }
  30. //通过双指针的思想
  31. private static boolean solution02() {
  32. String text = "上海自来水来自海上";
  33. //头指针
  34. int i = 0;
  35. //尾指针
  36. int j = text.length() - 1;
  37. //循环条件,头尾同时进行,首位匹配下一位,不同则返回false;
  38. while (true) {
  39. if (text.charAt(i) == text.charAt(j)) {
  40. i++;
  41. j--;
  42. } else {
  43. return false;
  44. }
  45. //尾指针要小于等于头指针
  46. if (j <= i) {
  47. return true;
  48. }
  49. }
  50. }
  51. }

2.关于括号匹配问题

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

  1. //括号匹配
  2. import java.util.HashMap;
  3. public class MatchBracket {
  4. public static void main(String[] args) {
  5. solution01();
  6. solution02();
  7. }
  8. //通过栈的思想解决
  9. private static void solution01() {
  10. String str = "{()[[()]]<>{}()<>}()";
  11. ArrayStack<Character> stack = new ArrayStack<>();
  12. //循环该数组下标,栈为空进栈
  13. for (int i = 0; i < str.length(); i++) {
  14. char c = str.charAt(i);
  15. if (stack.isEmpty()) {
  16. stack.push(c);
  17. } else {
  18. //当前栈顶
  19. char top = stack.peek();
  20. //通过ascll码匹配当满足条件时候,弹栈,即完成匹配
  21. if (top - c == -1 || top - c == -2) {
  22. stack.pop();
  23. } else {
  24. stack.push(c);
  25. }
  26. }
  27. }
  28. //当stack为空时候说明括号完全匹配
  29. System.out.println(stack.isEmpty());
  30. }
  31. //通过HashMap实现
  32. private static void solution02() {
  33. String str = "{()[[()]]<{()>}()";
  34. //给定hashmap的键值对应关系
  35. HashMap<Character,Character> map = new HashMap<>();
  36. map.put('[',']');
  37. map.put('<','>');
  38. map.put('(',')');
  39. map.put('{','}');
  40. ArrayStack<Character> stack = new ArrayStack<>();
  41. //遍历和法1相同
  42. for (int i = 0; i < str.length(); i++) {
  43. char c = str.charAt(i);
  44. if (stack.isEmpty()) {
  45. stack.push(c);
  46. } else {
  47. char top = stack.peek();
  48. //contains保证键值关系,包含时候,看c是否满足关系,满足时候弹栈,不满足继续入栈
  49. if (map.containsKey(top) && c == map.get(']')) {
  50. stack.pop();
  51. } else {
  52. stack.push(c);
  53. }
  54. }
  55. }
  56. System.out.println(stack.isEmpty());
  57. }
  58. }

3.简单计算器的实现

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

        3.1中缀表达式计算器

  1. //中缀表达式计算器
  2. public class InfixCalculator {
  3. public static void main(String[] args) {
  4. String expression = "(10+20/2*3)/2+8";
  5. try {
  6. int result = evaluateExpression(expression);
  7. System.out.println(result);
  8. } catch (Exception e) {
  9. e.printStackTrace();
  10. System.out.println("Wrong expression :" + expression);
  11. }
  12. }
  13. private static int evaluateExpression(String expression) {
  14. //需要两个辅助栈
  15. ArrayStack<Character> operatorStack = new ArrayStack<>();
  16. ArrayStack<Integer> numberStack = new ArrayStack<>();
  17. //格式化表达式
  18. expression = insertBlanks(expression);
  19. String[] tokens = expression.split(" ");
  20. for (String token : tokens) { //token == tokens[i]
  21. //过滤空串
  22. if (token.length() == 0) {
  23. continue;
  24. //遍历到 + - 号
  25. } else if (token.equals("+") || token.equals("-")) {
  26. while (!operatorStack.isEmpty() && (operatorStack.peek() == '+' || operatorStack.peek() == '-' || operatorStack.peek() == '*' || operatorStack.peek() == '/')) {
  27. //如果之前是别的+ - * / 则需要弹栈 并计算
  28. processAnOperator(numberStack, operatorStack);
  29. }
  30. //如果操作符栈为空 或者 不为空但栈顶为(
  31. operatorStack.push(token.charAt(0));
  32. //遍历到 * / 号
  33. } else if (token.equals("*") || token.equals("/")) {
  34. while (!operatorStack.isEmpty() && (operatorStack.peek() == '*' || operatorStack.peek() == '/')) {
  35. //如果之前是别的* / 则需要弹栈 并计算
  36. processAnOperator(numberStack, operatorStack);
  37. }
  38. //如果操作符栈为空 或者 不为空但栈顶为(
  39. operatorStack.push(token.charAt(0));
  40. //遍历到 (
  41. } else if (token.equals("(")) {
  42. operatorStack.push(token.charAt(0));
  43. //遍历到 )
  44. } else if (token.equals(")")) {
  45. //只要操作符栈的栈顶不是左括号( 就挨个弹栈计算即可
  46. while (operatorStack.peek() != '(') {
  47. processAnOperator(numberStack, operatorStack);
  48. }
  49. //最后 清掉左括号
  50. operatorStack.pop();
  51. //遍历到数字
  52. } else {
  53. numberStack.push(new Integer(token));
  54. }
  55. }
  56. //处理最后面的操作符
  57. while (!operatorStack.isEmpty()) {
  58. processAnOperator(numberStack, operatorStack);
  59. }
  60. return numberStack.pop();
  61. }
  62. //操作符栈弹栈一个元素 数字栈弹栈两个数字 进行计算 并将新的结果进栈到数字栈
  63. private static void processAnOperator(ArrayStack<Integer> numberStack, ArrayStack<Character> operatorStack) {
  64. char op = operatorStack.pop();
  65. int num1 = numberStack.pop();
  66. int num2 = numberStack.pop();
  67. //num2 op num1
  68. if (op == '+') {
  69. numberStack.push(num2 + num1);
  70. } else if (op == '-') {
  71. numberStack.push(num2 - num1);
  72. } else if (op == '*') {
  73. numberStack.push(num2 * num1);
  74. } else {
  75. numberStack.push(num2 / num1);
  76. }
  77. }
  78. //对原表达式进行格式化处理 给所有的非数字字符两边添加空格
  79. private static String insertBlanks(String expression) {
  80. StringBuilder sb = new StringBuilder();
  81. for (int i = 0; i < expression.length(); i++) {
  82. char c = expression.charAt(i);
  83. if (c == '(' || c == ')' || c == '+' || c == '-' || c == '*' || c == '/') {
  84. sb.append(' ');
  85. sb.append(c);
  86. sb.append(' ');
  87. } else {
  88. sb.append(c);
  89. }
  90. }
  91. return sb.toString();
  92. }
  93. }

        3.2后缀表达式计算器

        

  1. //后缀表达式的计算器
  2. public class SuffixCalculator {
  3. public static void main(String[] args) {
  4. String infixExpression = "(10+20/2*3)/2+8";
  5. String suffixExpression = InfixToSuffix.infixToSuffix(infixExpression);
  6. int result = evaluateSuffix(suffixExpression);
  7. System.out.println(result);
  8. }
  9. private static int evaluateSuffix(String expression) {
  10. ArrayStack<Integer> stack = new ArrayStack<>();
  11. String[] tokens = expression.split(" ");
  12. for (String token : tokens) {
  13. if (token.length() == 0) {
  14. continue;
  15. }
  16. if (isNumber(token)) {
  17. stack.push(new Integer(token));
  18. } else {
  19. processAnOperator(stack,token);
  20. }
  21. }
  22. return stack.pop();
  23. }
  24. private static void processAnOperator(ArrayStack<Integer> stack, String token) {
  25. int num1 = stack.pop();
  26. int num2 = stack.pop();
  27. if (token.equals("+")) {
  28. stack.push(num2 + num1);
  29. } else if (token.equals("-")) {
  30. stack.push(num2 - num1);
  31. } else if (token.equals("*")) {
  32. stack.push(num2 * num1);
  33. } else if (token.equals("/")) {
  34. stack.push(num2 / num1);
  35. }
  36. }
  37. private static boolean isNumber(String token) {
  38. return token.matches("\\d+");
  39. }
  40. }

        3.3中缀转换后缀

        

  1. //中缀表达式转后缀表达式
  2. public class InfixToSuffix {
  3. public static void main(String[] args) {
  4. String expression = "(10+20/2*3)/2+8";
  5. expression = infixToSuffix(expression);
  6. System.out.println(expression);
  7. }
  8. private static String infixToSuffix(String expression) {
  9. //操作符的栈
  10. ArrayStack<String> opStack = new ArrayStack<>();
  11. //后缀表达式的线性表
  12. ArrayList<String> suffixList = new ArrayList<>();
  13. //格式化表达式
  14. expression = insertBlanks(expression);
  15. String[] tokens = expression.split(" ");
  16. for (String token : tokens) {
  17. //过滤空串
  18. if (token.length() == 0) {
  19. continue;
  20. }
  21. //判断操作符+ - * /
  22. if (isOperator(token)) {
  23. /*
  24. 什么时候操作符进栈?
  25. 1.如果栈为空
  26. 2.如果栈顶是 (
  27. 3.如果栈顶是操作符,且优先级比当前token小
  28. 什么时候需要将栈顶操作符出栈?
  29. 1.栈顶操作符的优先级 >= 当前token
  30. */
  31. while (true) {
  32. if (opStack.isEmpty() || opStack.peek().equals("(") || priority(opStack.peek()) < priority(token)) {
  33. opStack.push(token);
  34. break;
  35. }
  36. suffixList.add(opStack.pop());
  37. }
  38. } else if (token.equals("(")) {
  39. opStack.push(token);
  40. } else if (token.equals(")")) {
  41. while (!opStack.peek().equals("(")) {
  42. suffixList.add(opStack.pop());
  43. }
  44. opStack.pop();
  45. } else if (isNumber(token)) {
  46. suffixList.add(token);
  47. } else {
  48. throw new IllegalArgumentException("wrong char :" + expression);
  49. }
  50. }
  51. while (!opStack.isEmpty()) {
  52. suffixList.add(opStack.pop());
  53. }
  54. //将数字元素和操作符元素进行拼接
  55. StringBuilder sb = new StringBuilder();
  56. for (int i = 0; i < suffixList.size(); i++) {
  57. sb.append(suffixList.get(i));
  58. sb.append(' ');
  59. }
  60. return sb.toString();
  61. }
  62. private static int priority(String token) {
  63. if (token.equals("+") || token.equals("-")) {
  64. return 0;
  65. }
  66. if (token.equals("*") || token.equals("/")) {
  67. return 1;
  68. }
  69. return -1;
  70. }
  71. private static boolean isNumber(String token) {
  72. return token.matches("\\d+");
  73. }
  74. private static boolean isOperator(String token) {
  75. return token.equals("+") || token.equals("-") || token.equals("*") || token.equals("/");
  76. }
  77. //对原表达式进行格式化处理 给所有的非数字字符两边添加空格
  78. private static String insertBlanks(String expression) {
  79. StringBuilder sb = new StringBuilder();
  80. for (int i = 0; i < expression.length(); i++) {
  81. char c = expression.charAt(i);
  82. if (c == '(' || c == ')' || c == '+' || c == '-' || c == '*' || c == '/') {
  83. sb.append(' ');
  84. sb.append(c);
  85. sb.append(' ');
  86. } else {
  87. sb.append(c);
  88. }
  89. }
  90. return sb.toString();
  91. }
  92. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/611819
推荐阅读
相关标签
  

闽ICP备14008679号