目录:

  • 什么是栈?
  • 栈有什么特性?
  • 栈怎么实现?(静态栈、动态栈)
  • 栈具体应用?

正文:

什么是栈?

栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。
这一端被称为栈顶,相对地,把另一端称为栈底。
向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;
从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

栈有什么特性?

1. 栈是允许在同一端进行插入和删除操作的特殊线性表
2. 遵循先进后出(后进先出)的原则
3. 栈具有记忆作用,对栈插入与删除操作中,不需要改变栈底的指针

栈怎么实现?

栈也分为静态栈和动态栈:
静态栈一般用数组表示,大小固定。
动态栈,一般用链表表示,大小自动扩容。

接下来对两种栈类型都进行代码实操运行:

创建栈接口类:

/**
 * 栈接口类
 * @author gxw
 * @date 2021/11/7 晚上22:14
 */
public interface Stack {

    //进栈方法
    void push(Object g);

    //出栈方法
    Object pop();

    //获取栈顶数据,但不移除
    Object peek();

    //获取栈总数
    int getSize();

    //返回栈是否为空
    boolean isEmpty();

    //展示栈
    void display();
}

动态栈实现类:

/**
 * 动态栈:大小可以自动扩容
 * 动态栈依赖于链表,所以我们需要用到Node结点类
 * @author gxw
 * @date 2021/11/7 晚上22:32
 */
public class DynamicStack implements Stack {
    //声明动态栈
    private Node topStack = new Node();

    //栈总数
    private int size;
    @Override
    public void push(Object g) {
        if(size == 0)
            topStack.setData(g);
        else {
            //声明新栈顶
            Node newTop = new Node();
            //设置新栈顶值
            newTop.setData(g);
            //设置新栈顶的下一个结点
            newTop.setNext(topStack);
            //然后新栈顶正式上位栈顶
            topStack = newTop;
        }
        size++;
    }

    @Override
    public Object pop() {
        //获取栈顶数据
        Object topData = topStack.getData();
        //然后出栈,将旧栈顶出栈,下一个结点自动成为新栈顶
        Node newTopStack = topStack.getNext();
        topStack = newTopStack;
        size--;
        return topData;
    }

    @Override
    public int getSize() {
        return size;
    }

    @Override
    public Object peek() {
        if(size == 0)
            return null;
        return topStack.getData();
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public void display() {
        Node topStack2 = topStack;
        System.out.println("展示栈");
        for (int i = 0;i < size;i++){
            System.out.print(topStack2.getData());
            System.out.print(" ");
            topStack2 = topStack2.getNext();
        }
        System.out.println("");
    }
}

动态栈依赖的Node结点类:

/**
 * 单链表采用了结点,所以需要以下定义
 * 主要两个属性,一个是数据域(存放数据内容),一个是指针域(存放下一个的结点的地址)
 */
public class Node {
    //数据域
    private Object data;
    //指针域
    private Node next;

    public Node(){
        this.data = new Object();
        this.next = null;
    }

    public Node(Object data, Node next){
        this.data = data;
        this.next = next;
    }

    public Node(Object data){
        this.data = data;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }
}

静态栈实现类:

/**
 * 静态栈:有固定大小的栈(一般以数组实现)
 * @author gxw
 * @date 2021/11/7 23:25
 */
public class StaticStack implements Stack {
    //静态栈数组
    private Object[] staticStack;

    //栈顶角标
    private int topIndex = -1;

    //栈现在长度
    private int size;

    //静态栈最大长度
    private int maxSize;

    /*
    构造方法,初始构建静态栈
     */
    public StaticStack(int maxSize){
        if(maxSize < 0)
            return;
        //初始静态栈数组
        this.staticStack = new Object[maxSize];
        this.maxSize = maxSize;
    }

    @Override
    public void push(Object g) {
        //如果静态栈满了,不可再入栈
        if(size == maxSize)
            return;

        //在栈顶入栈,并栈顶角标加1
        staticStack[++topIndex] = g;
        //长度加一
        size++;
    }

    @Override
    public Object pop() {
        //如果是空栈,不可出栈
        if (size == 0)
            return null;
        //出栈,并栈顶角标减1
        Object data = staticStack[topIndex--];
        //长度减1
        size--;
        return data;
    }

    @Override
    public int getSize() {
        return size;
    }

    @Override
    public Object peek() {
        if(size == 0)
            return null;
        return staticStack[topIndex];
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public void display() {
        System.out.println("展示静态栈:");
        for (int i = topIndex;i >= 0;i--){
            System.out.print(staticStack[i]);
            System.out.print(" ");
        }
        System.out.println("");
    }
}

测试:

public static void main(String[] args) {
    /**
     * 动态栈
     */
    //初始构建动态栈
    System.out.println("********初始化动态栈:********");
    DynamicStack dynamicStack = new DynamicStack();

    //入栈
    System.out.println("入栈hello world!:");
    dynamicStack.push("hello ");
    dynamicStack.push("world!");
    dynamicStack.display();

    //获取栈总数
    System.out.println("获取栈总数:");
    System.out.println(dynamicStack.getSize());

    //出栈
    System.out.println("出栈一次");
    System.out.println("出栈值:" + dynamicStack.pop());
    dynamicStack.display();

    //获取栈总数
    System.out.println("获取栈总数:");
    System.out.println(dynamicStack.getSize());

    /**
     * 静态栈
     */
    //初始化静态栈
    System.out.println("********初始化静态栈:********");
    StaticStack staticStack = new StaticStack(10);

    //入栈 hello world!
    System.out.println("入栈 hello world!:");
    staticStack.push("hello ");
    staticStack.push("world!");
    staticStack.display();

    //获取栈总数
    System.out.println("获取静态栈总数:");
    System.out.println(staticStack.getSize());

    //出栈一次
    System.out.println("出栈一次:");
    System.out.println("出栈值:" + staticStack.pop());
    staticStack.display();

    //获取栈总数
    System.out.println("获取静态栈总数:");
    System.out.println(staticStack.getSize());
}

结果:

image.png

栈具体怎么应用?

例如:面试官:请判断({[]}),({[]]}),(({[]})这三组括号都是否合规,时间复杂度为O(logn)!
解析:看到这个问题,我相信你脑中肯定有很多实验的结果,但你会发现除了栈,
其它的都很复杂,而只有栈的原则,反而使这个问题很简单。
我们遇到(,{,[,我们都进栈,只要遇到).},]这样的右括号就出栈,进行匹配判断即可!

接下来,我们通过代码实操来看下:

 /**
     * 判断括号组是否合规 例如:不合规的:({[}), 合规的:({[]})
     * @param str
     * @return
     */
    public static boolean isCorrectForBracketStr(String str){
        //声明栈,在此用静态栈
        StaticStack staticStack = new StaticStack(str.length());
        //将括号组字符串转换成字符数组
        char[] chars = str.toCharArray();
        for (int i = 0;i < chars.length;i++){
            char c = chars[i];
            if(c == '(' || c == '[' || c == '{'){
                //入栈
                staticStack.push(c);
//                staticStack.display();
            }else if(c == ')' || c == ']' || c == '}'){
                //判断是否为空栈,如果是空栈,直接匹配到了右括号,则代表括号组不符合规范,返回错误
                if(staticStack.getSize() == 0)
                    return false;

                //取出栈顶值,进行判断,如果栈顶和c括号相匹配,则将栈顶出栈,反之 不合规
                if(c == ')'){
                    if("(".equals(staticStack.peek().toString())){
                        //出栈
                        staticStack.pop();
//                        staticStack.display();
                    }else{
                        return false;
                    }
                }

                if(c == '}'){
                    if("{".equals(staticStack.peek().toString())){
                        //出栈
                        staticStack.pop();
//                        staticStack.display();
                    }else{
                        return false;
                    }
                }

                if(c == ']'){
                    if("[".equals(staticStack.peek().toString())){
                        //出栈
                        staticStack.pop();
//                        staticStack.display();
                    }else{
                        return false;
                    }
                }

                //判断栈和括号组是否匹配完,如果栈空,符号组也到最后,说明合规,反之,则不合规
                //判断字符组是否到最后
                if(i == chars.length - 1){
                    //判断栈是否为空了
                    if(staticStack.getSize() == 0){
                        return true;
                    }else{
                        return false;
                    }
                }else{
                    //如果字符组还有,但栈先空了,说明右括号比左括号多,不符合
                    if(staticStack.getSize() == 0)
                        return false;
                }

            }
        }
        return false;
    }

测试:

public static void main(String[] args) {
    //括号组字符串
    String str = "({[]})";
    System.out.println(str + " 字符组是否合规:" + isCorrectForBracketStr(str));

    //括号组字符串
    String str2 = "({[]]})";
    System.out.println(str2 + " 字符组是否合规:" + isCorrectForBracketStr(str2));

    //括号组字符串
    String str3 = "(({[]})";
    System.out.println(str3 + " 字符组是否合规:" + isCorrectForBracketStr(str3));
}

结果:

image.png

——————————————END——————————————————
本文为学习中的总结,希望可以帮助的诸位,如果贵人有发现文章有错误之处,还请麻烦指出,谢谢!


稳之楠
130 声望26 粉丝

行之稳,为之楠!