数据结构之栈

1.概念

栈(Stack):一种特殊的线性结构,其只允许固定的一段进行插入和删除元素操作。进行数据插入和删除的操作的一段称为栈顶,另一端称为栈底。栈中的元素遵守后进先出LIFO(Last In First Out)的原则。

相关操作

压栈:栈的插入操作叫做进栈、压栈、入栈,入数据在栈顶。

出栈:栈的删除操作叫做出栈。出数据在栈顶

数据结构之栈_第1张图片

如现实中的例子,先装进弹夹的子弹是最后出弹夹的。

数据结构之栈_第2张图片

先被放的盘子是最后拿走的。

数据结构之栈_第3张图片

2.栈的使用

//栈的使用
public class Test {
    public static void main(String[] args) {
        //无参构造
        Stack s = new Stack<>();
        //入栈
        System.out.println("=============入栈操作=================");
        s.push(1);
        s.push(2);
        s.push(3);
        s.push(4);
        System.out.println(s);
        System.out.println("=============出栈操作==================");
        int a = s.pop();
        System.out.println(a);
        System.out.println(s);//出栈后元素将不存在
        System.out.println("=============窥探操作==================");
        int b = s.peek();
        System.out.println(b);
        System.out.println(s);//如果只是简单窥探,不会让元素消失
        System.out.println("============获取元素个数================");
        System.out.println(s.size());
        System.out.println("============清空栈=====================");
        s.clear();
        System.out.println(s);

    }
}

这就是栈的常用的操作,基本就是入栈和出栈

3.栈的模拟实现

我们要明白Stack继承Vector,Vector和ArrayList类似,都是动态的顺序表,不同的是Vector是线程安全的。

package Demo1;

import java.util.Arrays;

/**
 * Describe:
 * User:lenovo
 * Date:2023-01-09
 * Time:16:30
 */

//栈的模拟实现
public class MyStack {
    int[] array;
    int size;

    //无参构造
    public MyStack() {
        array = new int[3];
    }

    //入栈
    public int push(int e) {
        ensureCapacity();
        array[size] = e;
        size++;
        return e;
    }
    //确定空间
    private void ensureCapacity() {
        if(!isFull()) {
            return;
        }
        grow();
    }
    //判断空间是否满了
    private boolean isFull() {
        if(size == array.length) {
            return true;
        }
        return false;
    }
    //扩大空间
    private void grow() {
        int newlength = (int)(array.length * 1.5);
        if(newlength > 10000) {
            newlength = 10000;
        }
        int[] newArray = new int[newlength];
        array = Arrays.copyOf(array, newlength);
    }

    //出栈
    public int pop(){
        if(size <= 0) {
            throw new RuntimeException("栈为空,无法进行出栈操作");
        }
        int e = peek();
        size--;
        return e;
    }

    //窥探
    public int peek() {
        if(size <= 0) {
            throw new RuntimeException("栈为空,无法进行peek()操作");
        }
        int e = array[size - 1];
        return e;
    }

    //获取栈的长度
    public int size() {
        return size;
    }

    //判断栈是否为空
    public boolean empty() {
        return size == 0;
    }

    //清空栈
    public void clear() {
        size = 0;
    }

    //检测
    public static void main(String[] args) {
        MyStack s = new MyStack();
        s.push(1);
        s.push(2);
        s.push(3);
        s.push(4);
        s.push(5);
        s.push(6);
        System.out.println(s.peek());
        System.out.println(s.pop());
        System.out.println(s.size());
    }

}

4.栈的应用场景

    • 改变元素的序列

1.若进栈的序列为1,2,3,4,进栈的时候可以出栈,下列不可能的出栈顺序是()
A.1,4,3,2 B.2,3,4,1 C.3,1,4,2 D.3,4,2,1
2.一个栈的初始状态为空。现将元素1、2、3、4、5、A、B、C、D、E依次入栈,然后依次出栈,则元素出栈的顺序是()

2.将递归改为循环

比如逆序打印单向链表

//逆序打印单向链表
class Node {
    int val;
    Node next;

    public Node() {
    }

    public Node(int val) {
        this.val = val;
    }
}


public class Test {
    //递归
    void printList(Node head) {
        if(head == null) {
            return;
        }
        printList(head.next);
        System.out.print(head.val + " ");
    }
    //循环
    void printList1(Node head) {
        Stack s = new Stack<>();
        Node cur = head;
        while(cur != null) {
            s.push(cur.val);//入栈
            cur = cur.next;
        }
        int size = s.size();
        for (int i = 0; i < size; i++) {
            System.out.print(s.pop() + " ");
        }
        System.out.println();
        
    }
}

3.括号匹配

class Solution {
    public boolean isValid(String s) {
        Stack stack = new Stack<>();
        //我们将左括号放进栈中,遇到右括号,将栈中元素弹出,进行匹配
        int i = 0;
        int length = s.length();
        for (i = 0; i < length; i++) {
            char tmp = s.charAt(i);
            if(tmp == '(' || tmp == '[' || tmp == '{') {
                stack.push(tmp);
            }else {
                if(stack.empty()) {
                    return false;
                }
                char tmp1 = stack.pop();
                if(!(tmp == ')' && tmp1 == '(' ||
                tmp == ']' && tmp1 == '[' ||
                tmp == '}' && tmp1 == '{')) {
                    return false;
                }
            }
        }
        if(i == length && stack.empty()) {
            return true;
        }
        return false;

    }
}

4.逆波兰表达式求值

首先我们要解释一下什么是逆波兰表达式。

如:1+(12+2)*1-5求出它的逆波兰表达式。

数据结构之栈_第4张图片

最后我们得到这样的表达式,如果遇到数组,我们把数字放到栈中,如果遇到符号,我们弹出两个元素进行操作,得到的结果放入栈中,直到最后所有元素走完。

数据结构之栈_第5张图片
数据结构之栈_第6张图片

我们看我们要写的题:逆波兰表达式求值。

class Solution {
    public int evalRPN(String[] tokens) {
        int length = tokens.length;
        Stack stack = new Stack<>();
        for (int i = 0; i < length; i++) {
            String key = tokens[i];
            if(key.equals("+") || key.equals("-") 
                    || key.equals("*") || key.equals("/")) {
                int num2 = stack.pop();//我们先弹出来的数字是操作符右边的数字
                int num1 = stack.pop();
                int ret = 0;
                if(key.equals("+")) {
                    ret = num1 + num2;
                }else if(key.equals("-")) {
                    ret = num1 - num2;
                }else if(key.equals("*")) {
                    ret = num1 * num2;
                }else if(key.equals("/")) {
                    ret = num1 / num2;
                }
                stack.push(ret);
            }else {
                int val = Integer.valueOf(key);
                stack.push(val);
            }
        }
        return stack.pop();

    }
}

5.出栈入栈顺序匹配

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等,数组长度相同。判断第二个序列是否是弹出的顺序。

import java.util.ArrayList;
import java.util.Stack;

public class Solution {
    public boolean IsPopOrder(int [] pushA,int [] popA) {
        int length = pushA.length;
        int i = 0;
        int j = 0;
        Stack stack = new Stack<>();
        while (i < length) {
            if(!stack.empty() && stack.peek() == popA[j]) {
                stack.pop();
                j++;
            }else {
                stack.push(pushA[i]);
                i++;
            }
            
        }
        if(stack.empty()) {
            return true;
        }else {
            while(j < length) {
                if(stack.pop() != popA[j]) {
                    return false;
                }
                j++;
            }
        }
        return true;
    }
}

6.最小栈

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

MinStack() 初始化堆栈对象。

void push(int val) 将元素val推入堆栈。

void pop() 删除堆栈顶部的元素。

int top() 获取堆栈顶部的元素。

int getMin() 获取堆栈中的最小元素。

//设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
class MinStack {
    private int[] data;
    private int size;
    private int[] minNum;

    public MinStack() {
        data = new int[10];
        minNum = new int[10];
    }

    public void push(int val) {
        if(size == data.length) {
            data = Arrays.copyOf(data, 2*data.length);
            minNum = Arrays.copyOf(minNum, 2*minNum.length);
        }
        data[size] = val;
        if(size == 0) {
            minNum[size] = val;
        }else if(minNum[size - 1] < val) {
            minNum[size] = minNum[size - 1];
        }else {
            minNum[size] = val;
        }
        size++;

    }

    public void pop() {
        size--;
    }

    public int top() {
        return data[size - 1];

    }

    public int getMin() {
        return minNum[size - 1];

    }
}

你可能感兴趣的:(java,笔记,java,数据结构)