java 实现 stack详解及实例代码

栈是限制插入和删除只能在一个位置上进行的 List,该位置是 List 的末端,叫做栈的顶(top),对于栈的基本操作有 push 和 pop,前者是插入,后者是删除。

栈也是 FIFO 表。

栈的实现有两种,一种是使用数组,一种是使用链表。

public class MyArrayStack<E> {

 private ArrayList<E> list = new ArrayList<>();

 public void push(E e) {
 list.add(e);
 }

 public E pop() {
 return list.remove(list.size() - 1);
 }

 public E peek() {
 return list.get(list.size() - 1);
 }

 public boolean isEmpty() {
 return list.size() == 0;
 }
}

public class MyLinkStack<E> {

 LinkedList<E> list = new LinkedList<>();

 public void push(E e) {
 list.addLast(e);
 }

 public E pop() {
 return list.removeLast();
 }

 public E peek() {
 return list.getLast();
 }

 public boolean isEmpty() {
 return list.size() == 0;
 }
}

栈的应用

平衡符号

给定一串代码,我们检查这段代码当中的括号是否符合语法。

例如:[{()}] 这样是合法的,但是 [{]}() 就是不合法的。

如下是测试代码:

public class BalanceSymbol {

 public boolean isBalance(String string) {
 MyArrayStack<Character> stack = new MyArrayStack<>();
 char[] array = string.toCharArray();
 for (char ch : array) {
  if ("{[(".indexOf(ch) >= 0) {
  stack.push(ch);
  } else if ("}])".indexOf(ch) >= 0) {
  if (isMatching(stack.peek(), ch)) {
   stack.pop();
  }
  }
 }

 return stack.isEmpty();
 }

 private boolean isMatching(char peek, char ch) {
 if ((peek == '{' && ch == '}') || (peek == '[' && ch == ']') || (peek == '(' && ch == ')')) {
  return true;
 }
 return false;
 }

 public static void main(String[] args) {
 BalanceSymbol symbol = new BalanceSymbol();
 String string = "public static void main(String[] args) {BalanceSymbol symbol = new BalanceSymbol();}";
 String string2 = "public static void main(String[] args) {BalanceSymbol symbol = new BalanceSymbol([);}]";
 System.out.println(symbol.isBalance(string));
 System.out.println(symbol.isBalance(string2));
 }
}

后缀表达式

例如一个如下输入,算出相应的结果,

3 + 2 + 3 * 2 = ?

这个在计算顺序上不同会产生不同的结果,如果从左到右计算结果是 16,如果按照数学优先级计算结果是 11。

如果把上述的中缀表达式转换成后缀表达式:

3 2 + 3 2 * +

如果使用后缀表达式来计算这个表达式的值就会非常简单,只需要使用一个栈。

每当遇到数字的时候,把数字入栈。

每当遇到操作符,弹出2个元素根据操作符计算后,入栈。

最终弹出栈的唯一元素就是计算结果。

/**
 * 简化版本,每个操作数只一位,并且假设字符串合法
 */
public class PostfixExpression {

 public static int calculate(String string) {
 MyArrayStack<String> stack = new MyArrayStack<>();

 char[] arr = string.toCharArray();

 for (char ch : arr) {
  if ("0123456789".indexOf(ch) >= 0) {
  stack.push(ch + "");
  } else if ("+-*/".indexOf(ch) >= 0) {
  int a = Integer.parseInt(stack.pop());
  int b = Integer.parseInt(stack.pop());
  if (ch == '+') {
   stack.push((a + b) + "");
  } else if (ch == '-') {
   stack.push((a - b) + "");
  } else if (ch == '*') {
   stack.push((a * b) + "");
  } else if (ch == '/') {
   stack.push((a / b) + "");
  }
  }
 }
 return Integer.parseInt(stack.peek());
 }

 public static void main(String[] args) {
 System.out.println(calculate("32+32*+"));
 }
}

中缀表达式转换成后缀表达式

假设只运行 +,-,*,/,() 这几种表达式。并且表达式合法。

a + b * c - (d * e + f) / g 转换后的后缀表达式如下:

a b c * + d e * f + g / -

使用栈中缀转后缀步骤如下:

  1. 当读到操作数立即把它输出
  2. 如果遇到操作符入栈,如果遇到的左括号也放到栈中
  3. 如果遇到右括号,就开始弹出栈元素,直到遇到对应的左括号,左括号只弹出不输出。
  4. 如果遇到其他符号,那么从栈中弹出栈元素知道发现优先级更低的元素为止。
import java.util.HashMap;
import java.util.Map;

public class ExpressionSwitch {

 private static Map<Character, Integer> map = new HashMap<Character, Integer>();

 static {
 map.put('+', 0);
 map.put('-', 1);
 map.put('*', 2);
 map.put('/', 3);
 map.put('(', 4);
 }

 private static char[][] priority = {
  // 当前操作符
  //    +  -  *  /  (
  /* 栈 + */{ '>', '>', '<', '<', '<'},
  /* 顶 - */{ '>', '>', '<', '<', '<'},
  /* 操 * */{ '>', '>', '>', '>', '<'},
  /* 作 / */{ '>', '>', '>', '>', '<'},
     /* 符 ( */{ '<', '<', '<', '<', '<'},
 };

 public static String switch1(String string) {
 StringBuilder builder = new StringBuilder();

 char[] arr = string.toCharArray();

 MyArrayStack<Character> stack = new MyArrayStack<>();
 for (char ch : arr) {
  if ("0123456789abcdefghijklmnopqrstuvwxyz".indexOf(ch) >= 0) {
  builder.append(ch);
  } else if ('(' == ch) {
  stack.push(ch);
  } else if (')' == ch) {
  while (true && !stack.isEmpty()) {
   char tmp = stack.pop();
   if (tmp == '(') {
   break;
   } else {
   builder.append(tmp);
   }
  }
  } else {
  while (true) {
   if (stack.isEmpty()) {
   stack.push(ch);
   break;
   }
   char tmp = stack.peek();
   if (isPriorityHigh(tmp, ch)) {
   builder.append(stack.pop());
   } else {
   stack.push(ch);
   break;
   }
  }
  }
 }

 while(!stack.isEmpty()) {
  builder.append(stack.pop());
 }

 return builder.toString();
 }

 private static boolean isPriorityHigh(char tmp, char ch) {
 return priority[map.get(tmp)][map.get(ch)] == '>';
 }

 public static void main(String[] args) {
 System.out.println(switch1("a+b*c-(d*e+f)/g"));
 }
}

通过此文,希望大家对Java stack 的知识掌握,谢谢大家对本站的支持!

(0)

相关推荐

  • Java ArrayDeque实现Stack的功能

    在J2SE6引入了ArrayDeque类,它继承了Deque(双向队列)接口,使用此类可以自己实现java.util.Stack类的功能,去掉了java.util.Stack的多线程同步的功能. 例如创建一个存放Integer类型的Stack,只要在类中创建一个ArrayDeque类的变量作为属性,之后定义的出栈.入栈,观察栈顶元素的操作就直接操作ArrayDeque的实例变量即可. import java.util.ArrayDeque; import java.util.Deque; pub

  • java自带的工具Jstack截取进程中的堆栈信息

    在Java软件的使用过程中,有时会莫名的出现奇怪的问题.而这些问题常常无法使用日志信息定位,这时我们就需要通过查看进程内部线程的堆栈调用关系来分析问题出在哪里. 举个例子,当我们在做某个操作时,莫名的会弹出多个警告框,其中有些信息是正常的,有些则不是.对于这些错误的警告信息,我们该如何定位是哪个位置的代码出现了错误弹出的框呢? 我们就需要在弹框以后,去查看软件的各个线程,去查找究竟是哪个线程导致了该问题.可是有时因为环境.时间等问题,我们根本不能拿着IDE去调试, 只能通过工具软件拍下内存快照,

  • 输出java进程的jstack信息示例分享 通过线程堆栈信息分析java线程

    复制代码 代码如下: #!/bin/shpro_name=java #process namekeys=`ps -ef |grep "$pro_name" |grep -v "grep" | awk '{print $2}'`nowdate=`date +%Y%m%d%H%M%S` jstackpath="/usr/java/jdk1.6.0_07/bin/jstack"cpulogpath="/home/" for key

  • JAVA Stack详细介绍和示例学习

    第1部分 Stack介绍Stack是栈.它的特性是:先进后出(FILO, First In Last Out).java工具包中的Stack是继承于Vector(矢量队列)的,由于Vector是通过数组实现的,这就意味着,Stack也是通过数组实现的,而非链表.当然,我们也可以将LinkedList当作栈来使用! Stack的继承关系Stack和Collection的关系如下图:Stack的构造函数Stack只有一个默认构造函数,如下: 复制代码 代码如下: Stack() Stack的API

  • 基于java中stack与heap的区别,java中的垃圾回收机制的相关介绍

    #. 在java中有两类内存.分别称为stack(堆栈)和heap(堆). stack是程序内存空间,因此所有的基本类型和对象的引用是存在stack中. heap是java虚拟机储存对象的,它是一个巨大的内存,当你创造一个对象,java虚拟机把对象放入heap中,把创造的对象的地址放入stack中. 因此,基本类型.对象的引用储存在stack中:对象储存在heap中. #. java中的垃圾回收机制 当你new一个新的对象,java分配必需的内存.当你用完一个对象时,java的垃圾回收器为你把内

  • java堆栈类使用实例(java中stack的使用方法)

    JAVA 中,使用 java.util.Stack 类的构造方法创建对象. public class Stack extends vector 构造方法 : public Stack() 创建一个空 Stack. 方法:  1. public push  (item )  把项 压入栈顶.其作用与 addElement (item ) 相同. 参数 item 压入栈顶的项 . 返回: item 参数 : 2. public pop () 移除栈顶对象,并作为函数的值 返回该对象. 返回:栈顶对象

  • java8 集合之Stack详解及实例

    java  集合之Stack 概要: Stack是栈,特性是先进后出(FILO,First In Last Out).Stack是继承于Vector(矢量队列),由于Vector是同数组实现的,Stack也是通过数组而非链表. Stack和Collection关系如下: 基于Java8的源代码: public class Stack<E> extends Vector<E> { public Stack() {//创建空栈 } public E push(E item) {//入栈

  • java 实现 stack详解及实例代码

    栈是限制插入和删除只能在一个位置上进行的 List,该位置是 List 的末端,叫做栈的顶(top),对于栈的基本操作有 push 和 pop,前者是插入,后者是删除. 栈也是 FIFO 表. 栈的实现有两种,一种是使用数组,一种是使用链表. public class MyArrayStack<E> { private ArrayList<E> list = new ArrayList<>(); public void push(E e) { list.add(e);

  • Java中自定义异常详解及实例代码

    Java中自定义异常详解及实例代码 下面做了归纳总结,欢迎批评指正 自定义异常 class ChushulingException extends Exception { public ChushulingException(String msg) { super(msg); } } class ChushufuException extends Exception { public ChushufuException(String msg) { super(msg); } } 自定义异常 En

  • java IO 字节流详解及实例代码

    java IO 字节流详解 1.         如何理解输入输出流? 这是我当初在学习Java IO这一块很难理解的一块,输入输出流我们可必须以一个为参照物:我们以内存为参照物,凡是写入内存的我们叫输入流,从内存中写出的我们叫输出流.看下面的示例图 有了这样的一个概念对于我们再学习Java中的IO流我相信就会变得特别简单了. 2.         再看流的分类 流的分类,Java的流分类比较丰富,刚接触的人看了后会感觉很晕.流分类的方式很多: 1.按照输入的方向分,输入流和输出流,输入输出的参

  • java LinkedList类详解及实例代码

    java  LinkedList类详解 LinkedList的特有功能 A:添加功能 public void addFirst(Object e); public void addLast(Object e); B:特有功能 public Object getFirst(); public Object getLast(); C:删除功能 public Object removeFirst(); public Object removeLast(); 实例代码: import java.util

  • java  LinkedList类详解及实例代码

    java  LinkedList类详解 LinkedList的特有功能 A:添加功能 public void addFirst(Object e); public void addLast(Object e); B:特有功能 public Object getFirst(); public Object getLast(); C:删除功能 public Object removeFirst(); public Object removeLast(); 实例代码: import java.util

  • Java instanceof用法详解及实例代码

    Java instanceof用法详解 Java 中的instanceof 运算符是用来在运行时指出对象是否是特定类的一个实例.instanceof通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例. 用法: result = object instanceof class 参数: Result:布尔类型. Object:必选项.任意对象表达式. Class:必选项.任意已定义的对象类. 说明: 如果 object 是 class 的一个实例,则 instanceof 运

  • java Super 用法详解及实例代码

    java  Super 用法详解 1)有人写了个很好的初始化属性的构造函数,而你仅仅想要在其中添加另一些自己新建属性的初始化,这样在一个构造函数中调用另外一个构造函数,可以避免重复的代码量,减少工作量: 2)在一个构造函数中调用另外一个构造函数的时候应该用的是同一块内存空间,在默认的构造函数中先初始化变量,调用另一个的时候覆写已经初始化的变量的值: 3)整个调用的过程和递归调用函数有点类似,不断充气球,直到整个气球膨胀起来,不断的深层递进,遇到停止标记,逐层的跳出来. 写了段代码,解释我上面的叙

  • java  Super 用法详解及实例代码

    java  Super 用法详解 1)有人写了个很好的初始化属性的构造函数,而你仅仅想要在其中添加另一些自己新建属性的初始化,这样在一个构造函数中调用另外一个构造函数,可以避免重复的代码量,减少工作量: 2)在一个构造函数中调用另外一个构造函数的时候应该用的是同一块内存空间,在默认的构造函数中先初始化变量,调用另一个的时候覆写已经初始化的变量的值: 3)整个调用的过程和递归调用函数有点类似,不断充气球,直到整个气球膨胀起来,不断的深层递进,遇到停止标记,逐层的跳出来. 写了段代码,解释我上面的叙

  • Java 反射机制详解及实例代码

    Java反射详解 本篇文章依旧采用小例子来说明,因为我始终觉的,案例驱动是最好的,要不然只看理论的话,看了也不懂,不过建议大家在看完文章之后,在回过头去看看理论,会有更好的理解. 下面开始正文. [案例1]通过一个对象获得完整的包名和类名 package Reflect; /** * 通过一个对象获得完整的包名和类名 * */ class Demo{ //other codes... } class hello{ public static void main(String[] args) {

  • Java 关键字static详解及实例代码

    一. static代表着什么 在Java中并不存在全局变量的概念,但是我们可以通过static来实现一个"伪全局"的概念,在Java中static表示"全局"或者"静态"的意思,用来修饰成员变量和成员方法,当然也可以修饰代码块. Java把内存分为栈内存和堆内存,其中栈内存用来存放一些基本类型的变量.数组和对象的引用,堆内存主要存放一些对象.在JVM加载一个类的时候,若该类存在static修饰的成员变量和成员方法,则会为这些成员变量和成员方法在固

随机推荐