赞
踩
栈(stack)是一种用于存储数据的简单数据结构。栈一个有序线性表,只能在表的一端(PS:栈顶)执行插人和删除操作。最后插人的元素将被第一个删除。所以,栈也称为后进先出(Last In First Out,LIFO)或先进后出(First In Last Out,FILO)线性表。
- 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();
- }
基于简单数组实现一个栈,其基本思路是这样的:从左至右向数组中添加所有的元素,并定义一个变量用来记录数组当前栈顶(top)元素的下标。当数组存满了栈元素时,执行入栈(插入元素)操作将抛出栈满异常;当对一个没有存储栈元素的数组执行出栈(删除元素)操作将抛出栈空异常,当然,这种实现方式有一个很明显的局限性。那就是:栈的最大空间必须预先声明且不能改变。试图对一个满栈执行入栈操作将会产生异常。
基于动态数组的实现一个栈,其基本思路跟上面类似。不同的是,这种方式下当数组中存储的元素达到一定量时(如:数组空间的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;
- }
- }
基于链表实现一个栈,其基本思路是这样的:通过在链表的表头插入元素的方式来实现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() + " ");
- }
- }
-
- }
- 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();
- }
- }
-
- }
是指一个线性表的两端当做栈底,分别进行入栈和出栈操作,主要利用了栈:栈底不变,栈顶变化的特征;
双端栈是线性表的一种,更是栈的一个特殊分类,可用借用动态数组+栈的组合实现。
- 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();
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。