07栈

1.概念

栈是一种操作受限的线性表,只允许在一端插入和删除数据. 先进后出 and 后进先出
个人感觉,栈可以使用 内部钱内部的场景,某个对象,在内部包含另一个完整的对象,比如 [()], 这对中括号,内部包含了一个完整的小括号对; 又如函数的层层调用,外部函数,包含了内部函数的全部过程。

2.分类

2.1顺序栈

用数组实现的栈叫顺序栈.

2.1.1 固定大小

package com.desmond.codebase.algorithm.stack;

import java.util.Stack;

/**
 * @author presleyli
 * @date 2018/12/24 12:57 PM
 */
public interface StackInterface<E> {
   E push(E e);

   E pop();

   E peek();
}

package com.desmond.codebase.algorithm.stack;

/**
 * 固定大小的顺序栈(数组栈).
 * @author presleyli
 * @date 2018/12/24 12:57 PM
 */
public class FixedSizeArrayStack implements StackInterface<String>{
    private String[] arr;
    private int size;

    public FixedSizeArrayStack(int n) {
        arr = new String[n];
    }

    /**
     * O(1)
     * @param s
     * @return
     */
    @Override
    public String push(String s) {
        if(size >= arr.length) {
            throw new RuntimeException("stack is full");
        }

        arr[size++] = s; // 1

        return s;
    }

    // O(1)
    @Override
    public String pop() {
        if(size == 0) {
            return null;
        }

        return arr[--size]; // 1
    }

    // O(1)
    @Override
    public String peek() {
        if(size == 0) { // 1
            return null;
        }

        int idx = size - 1; // 1
        return arr[idx]; //  1
    }

    @Override
    public String toString() {
        if(size > 0) {
            System.out.println("start___________");
            for(int i=size-1;i>=0;i--) {
                System.out.println(String.valueOf(arr[i]));
            }

            System.out.println("end______\n\n");
        }

        return "\n";
    }

    public static void main(String[] args) {
        FixedSizeArrayStack stack = new FixedSizeArrayStack(2);
        stack.push("a");
        System.out.println(stack);

        stack.push("b");
        System.out.println(stack);

        System.out.println("peek:" + stack.peek());
        System.out.println("peek:" + stack.peek());
        System.out.println(stack);

        System.out.println("pop:" + stack.pop());
        System.out.println(stack);

        System.out.println("pop:" + stack.pop());
        System.out.println(stack);

        System.out.println("pop:" + stack.pop());
        System.out.println(stack);
    }
}

2.1.2 可扩容

​ 利用数组的动态扩容。复杂度

  • 最好:O(1)

  • 最坏: O(n)

  • 均摊:O(1)

    package com.desmond.codebase.algorithm.stack;
    
    /**
     * 可自动扩容的顺序栈(数组栈).
     * @author presleyli
     * @date 2018/12/24 12:57 PM
     */
    public class ChangeableSizeArrayStack implements StackInterface<String>{
        private String[] arr;
        private int size;
        private final int SCALE = 2;
    
        public ChangeableSizeArrayStack(int n) {
            arr = new String[n];
        }
    
        /**
         * 最好:O(1)
         * 最坏:2n+3 -> O(n)
         * 均摊(摊还):O(1)
         * @param s
         * @return
         */
        @Override
        public String push(String s) {
            if(size >= arr.length) { // 1
                // 数组已满,扩容
                String[] newarr = new String[arr.length * SCALE]; // 1
    
                for(int i=0; i<arr.length; i++) { // n
                    newarr[i] = arr[i]; // n
                }
    
                arr = newarr;
            }
    
            arr[size++] = s; // 1
    
            return s;
        }
    
        @Override
        public String pop() {
            if(size == 0) {
                return null;
            }
    
            return arr[--size];
        }
    
        @Override
        public String peek() {
            if(size == 0) {
                return null;
            }
    
            int idx = size - 1;
            return arr[idx];
        }
    
        @Override
        public String toString() {
            if(size > 0) {
                System.out.println("start___________");
                for(int i=size-1;i>=0;i--) {
                    System.out.println(String.valueOf(arr[i]));
                }
    
                System.out.println("end______\n\n");
            }
    
            return "\n";
        }
    
        public static void main(String[] args) {
            ChangeableSizeArrayStack stack = new ChangeableSizeArrayStack(2);
            stack.push("a");
            System.out.println(stack);
    
            stack.push("b");
            System.out.println(stack);
    
            stack.push("c");
            System.out.println(stack);
    
            stack.push("d");
            System.out.println(stack);
    
            stack.push("e");
            System.out.println(stack);
    
            stack.push("f");
            System.out.println(stack);
    
            stack.push("g");
            System.out.println(stack);
    
            System.out.println("peek:" + stack.peek());
            System.out.println("peek:" + stack.peek());
            System.out.println(stack);
    
            System.out.println("pop:" + stack.pop());
            System.out.println(stack);
    
            System.out.println("pop:" + stack.pop());
            System.out.println(stack);
    
            System.out.println("pop:" + stack.pop());
            System.out.println(stack);
        }
    }
    
    

2.2链式栈

用链表实现的栈叫顺序栈.
package com.desmond.codebase.algorithm.stack;

import com.desmond.codebase.algorithm.link.Link;

/**
 * 链式栈.
 * @author presleyli
 * @date 2019/1/5 10:53 AM
 */
public class LinkStack implements StackInterface<String>{
    private Link<String> link = new Link<>();
    
    @Override
    public String push(String s) {
        link.add(s);
        
        return s;
    }

    @Override
    public String pop() {
        return link.remove(link.size() - 1);
    }

    @Override
    public String peek() {
        return link.index(link.size() - 1).getE();
    }
}

3.应用

3.1函数调用

3.2表达式中的应用

3.2.1 背景

​ 求四则运算 3+5*8-6 的值:取两个栈,一个放操作数,一个放运算符合。当放入运算符号时,判断如果之前的运算符的优先级大于当前时,先从操作数栈出栈两个操作数,并运用运算符进行运算,结果压入栈中,一直往复至最后一个元素

3.2.1 示意图

在这里插入图片描述

3.2.2 代码

package com.desmond.codebase.algorithm.stack;

import com.desmond.codebase.algorithm.stack.base.FixedSizeArrayStack;

import java.util.stream.Stream;

/**
 * 利用栈实现 四则运算符,
 *  3+5*8-6
 * @author presleyli
 * @date 2019/1/5 11:03 AM
 */
public class Operation {
    public static void main(String[] args) {
        System.out.println(op("3+5*8-6") + "-->" + "37");
        System.out.println(op("3+5") + "-->" + "8");
        System.out.println(op("5*8") + "-->" + "40");
        System.out.println(op("5*8-6") + "-->" + "34");
    }

    /**
     * O(1).
     * @param express
     * @return
     */
    public static Integer op(String express) {
        FixedSizeArrayStack eleStack = new FixedSizeArrayStack(5 );
        FixedSizeArrayStack opStack = new FixedSizeArrayStack(5);

        int result = 0;
        char[] arr = express.toCharArray();

        for(int i = 0; i < arr.length; i++) {
            char c = arr[i]; // 1

            OpEnum opEnum = OpEnum.getOp(c); // 1
            if(opEnum != null) {
                operations(eleStack, opEnum, opStack); // 1

                opStack.push(c + "");
            } else {
                eleStack.push(c + "");
            }

            if(i == arr.length - 1) {
                opEnum = OpEnum.getOp(opStack.pop().charAt(0));

                result = cal(opEnum, eleStack);
            }
        }

        return result;
    }

    /**
     * O(1).
     * @param eleStack
     * @param curr
     * @param opStack
     */
    private static void operations(FixedSizeArrayStack eleStack, OpEnum curr, FixedSizeArrayStack opStack) {
        if(eleStack.size() > 1 && opStack.size() > 0) {
            OpEnum existing = OpEnum.getOp(opStack.peek().charAt(0)); // 1
            if(existing.getPriority() >= curr.getPriority()) { // 1
                existing = OpEnum.getOp(opStack.pop().charAt(0));
                int result = cal(existing, eleStack);

                eleStack.push(result + "");

                operations(eleStack, curr, opStack);
            }
        }
    }

    /**
     * O(1)
     * @param oe
     * @param eleStack
     * @return
     */
    private static Integer cal(OpEnum oe, FixedSizeArrayStack eleStack) {
        int result = 0;

        int top1 = Integer.parseInt(eleStack.pop());
        int top2 = Integer.parseInt(eleStack.pop());

        switch (oe) {
            case ADD:
                result = top2 + top1;
                break;
            case SUBSTRACT:
                result = top2 - top1;
                break;
            case MULTIPLE:
                result = top2 * top1;
                break;
            case DIVIION:
                result = top2 / top1;
                break;
        }

        return result;
    }

    private static enum OpEnum {
        ADD('+', 1),
        SUBSTRACT('-', 1),

        MULTIPLE('*', 2),
        DIVIION('/', 2),
        ;


        private char op;
        private int priority;

        OpEnum(char op, int priority) {
            this.op = op;
            this.priority = priority;
        }

        public static OpEnum getOp(char c) {
            return Stream.of(OpEnum.values())
                    .filter(o -> o.getOp() == c)
                    .findFirst()
                    .orElse(null);
        }

        public char getOp() {
            return op;
        }

        public void setOp(char op) {
            this.op = op;
        }

        public int getPriority() {
            return priority;
        }

        public void setPriority(int priority) {
            this.priority = priority;
        }
    }
}

3.3 括号匹配

​ 判断表达中括号()/[]/{}是否一一匹配.

​ 代码:

package com.desmond.codebase.algorithm.stack;

import com.desmond.codebase.algorithm.stack.base.FixedSizeArrayStack;

/**
 * @author presleyli
 * @date 2019/1/5 11:59 AM
 */
public class BracketMatch {

    public static void main(String[] args) {
        System.out.println(isValid("a(([{}]))"));
        System.out.println(isValid("a(b[c{d}]}"));
        System.out.println(isValid("a(b[(c{d}]]}"));
        System.out.println(isValid("a(b{[c{d}]}"));
    }

    /**
     * O(1).
     * @param express
     * @return
     */
    public static boolean isValid(String express) {
        FixedSizeArrayStack stack = new FixedSizeArrayStack(10);

        for(int i = 0; i < express.length(); i++) {
            char c = express.charAt(i);

            if(c == '(' || c == '[' || c == '{') {
                stack.push(c + "");
            }

            if(c == ')' || c == ']' || c == '}') {
                char b = stack.pop().charAt(0);

                if(c == ')') {
                    if(b != '(') {
                        return false;
                    }
                }

                if(c == ']') {
                    if(b != '[') {
                        return false;
                    }
                }

                if(c == '}') {
                    if(b != '{') {
                        return false;
                    }
                }
            }

        }


        return stack.size() == 0;
    }
}

3.4 浏览器前进、后退

流程:
在这里插入图片描述

代码:

package com.desmond.codebase.algorithm.stack;

import com.desmond.codebase.algorithm.stack.base.FixedSizeArrayStack;
import com.desmond.codebase.algorithm.stack.base.StackInterface;

/**
 * 浏览器前进或者后推.
 * @author presleyli
 * @date 2019/1/5 12:38 PM
 */
public class BrowserAheadOrBack {
    static StackInterface<String> ahead = new FixedSizeArrayStack(5),
            back = new FixedSizeArrayStack(5);

    public static void main(String[] args) {
        init();

        ahead();
        ahead();

        back();
        back();
        back();
        back();
    }

    public static void init() {
        ahead.push("a");
        ahead.push("b");

        back.push("c");
    }

    public static void ahead() {
        if(back.size() > 0) {
            ahead.push(back.pop());
        }

        if(back.size() == 0) {
            System.out.println("last page!");
        }

        System.out.println("current: " + ahead.peek());
    }

    public static void back() {
        if(ahead.size() > 0) {
            back.push(ahead.pop());
        }

        if(ahead.size() == 0) {
            System.out.println("first page!");
        }

        System.out.println("current: " + ahead.peek());
    }
}

4. Jvm中的栈

​ 桢栈,包括局部变量表,操作数栈(存放操作数用于操作),动态链接,方法出口灯信息

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值