《栈与队列:数据结构的“双生花”》

《栈与队列:数据结构的"双生花"》

一.栈:后进先出

1.1认识栈

这一章的栈和队列比较简单;

首先是:后进先出的栈

我们可以把栈理解为简化版的顺序表,他最主要的就是三个操作:

①入栈------>尾插

②出栈------>尾删

③取栈顶元素

栈的方法:

入栈:push();
出栈:pop();
取栈顶元素:peek();

1.2后进先出

后进先出,这个不难理解,就是后入栈的元素,进行出栈或者取栈顶元素时,先处来,俗话说枪打出头鸟,后来者机会大,这就是后进先出;

代码演示:

java 复制代码
//实例化栈
Stack<Integer> stack = new Stack<>();
//注意这种引用类型存储的变量要写成包装类型;
//入栈
stack.push(1);
stack.push(2);
stack.push(3);
stack.push(4);
//出栈
int a = stack.pop();//这里是4;
System.out.println(a);//4
//取栈顶元素
System.out.println(stack.peek());//这里是3

1.3基于数组的栈模拟

①.入栈

java 复制代码
class MyArrayStack{
//首先创集一个数组
    private int[] data;
    private int size;
    
    public MyArrayStack(int size) {
        this.data = new int[size];
    }
    public MyArrayStack() {
        this.data = new int[10];
    }
    
    private void grow(){
        int[] Edata = new int[2*data.length];
        for (int i = 0; i < data.length; i++) {
            Edata[i] = data[i];
        }
        data = Edata;
    }
    //入栈模拟
    public void push(int val){
        if(data.length<=size){
            grow();
        }
        data[size] = val;
        size++;
    }
        }

②.出栈

java 复制代码
   public int pop(){
      if (size == 0) throw new RuntimeException("栈为空");
   //size先减减,扩容减一,然后返回栈顶元素
        return data[--size];
    }

③.取栈顶元素

java 复制代码
   public int peek(){
      if (size == 0) throw new RuntimeException("栈为空");
        return data[size-1];
    }

二.队列:先进先出

2.1认识队列

队列与栈不同,他是先进先出,也就是先入队列的`元素先出来,后来的慢慢排队,这个在我们日常生活中是很常见的,比如排队吃饭,肯定是先排在前面的先吃到饭,后排的后吃饭;

队列方法:

注意:队列他是接口,接口,接口!

这里我只说链表实现了这个接口,这是最常见,最常用的的向上转型,其他的以后再说;

java 复制代码
//用链表的向上转型
   Queue<Integer> queue = new LinkedList<>();
        queue.offer(1);
        queue.offer(2);
        queue.offer(3);
        int b = queue.poll();//1
        System.out.println(b);//打印出先进去的1

2.2队列图解

队列我们也是要掌握三种基本操作:入队列,出队列,取队首元素;
入队列-----尾插
出队列-----头删
取队首元素

2.3 以数组模拟队列

这里我们用不一样的方法,之前我们在写入栈方法时,他是属于动态内存,用完了,可以直接继续不断地扩容,这次我们用固定数组

首先创建头标head,尾标tail;

java 复制代码
public class MyArrayQueue {
    public int[] data;
    public int head = 0;
    public int tail = 0;
    public int size = 0;

    public MyArrayQueue(int count) {
        this.data = new int[count];
    }
    public MyArrayQueue() {
        this.data =  new int[10];
    }
    }

①入队列

java 复制代码
    public void offer(int val){
if(size==data.length){
    return ;//直接结束
}
if(tail == data.length){
    tail = 0;
}
data[tail] = val;
size++;
    }

②.出队列

java 复制代码
 public Integer poll(){
        if(size==0){
            return null;
        }
        int res = data[head];
        head++;
        if(head == data.length){
            head = 0;
        }
        size--;
        return res;
    }

③.取队首元素

java 复制代码
    public Integer peek(){
        if(size==0){
            return null;
        }
        return data[head];
    }

2.4以链表模拟队列

首先创建链表节点;

java 复制代码
class ELinkedNode{
  public int val;
  public ELinkedNode next;
    public ELinkedNode(int val) {
        this.val = val;
        this.next = null;
    }
}

①入队列

java 复制代码
public class MyLinkedQueue {
    ELinkedNode head = null;
    ELinkedNode tail = null;
    public void offer(int val){
        ELinkedNode newNode = new ELinkedNode(val);
        if(head == null){
            tail = newNode;
            head = newNode;
            return;
        }
        tail.next = newNode;
        tail = tail.next;
    }
}

②出队列

java 复制代码
    public Integer poll(){
        if(head==null){
            return null;
        }
        ELinkedNode cur = head;
        head = head.next;
        return cur.val;
    }

③取队首元素

java 复制代码
    public Integer peek(){
        if(head==null){
            return null;
        }
        return head.val;
    }

三.栈和队列题目

1. 括号匹配

括号匹配

题目分析

1).首先判断符号十分时左括号,如果说,直接入栈

2).还需要判断是否右括号,不然直接返回false;

3).最后依次出栈与右括号比较是否配对

4)返回栈是否为空.为空左右括号都匹配到了

java 复制代码
    public boolean isMatch(char str1,char str2){
        if(str1=='('&&str2==')'){
            return true;
        }
        if(str1=='['&&str2==']'){
            return true;
        }
        if(str1=='{'&&str2=='}'){
            return true;
        }
        return false;
    }
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        for(int i = 0;i<s.length();i++){
            char ch = s.charAt(i);
if(ch=='('||ch=='['||ch=='{'){
    stack.push(ch);
    continue;
}
if(ch!=')'&&ch!='}'&&ch!=']'){
    return false;
}
if(stack.empty()){
    return false;
}
char str = stack.peek();
if(isMatch(str,ch)){
    stack.pop();
    continue;
}
return false;
        }
        return stack.empty();
    }

2. 逆波兰表达式求值

逆波兰表达式求值

题目解析

1).首先判断是否为数字,如果是直接入栈;

2).数字和符号都不是,continue,这个题其实不用考虑,但我们还是要写全部

3).接着判断是加减乘除,拿出两个元素,进行计算

java 复制代码
    public boolean isnumber (String str){
        if(str.equals("+")||str.equals("-")||str.equals("*")||str.equals("/")){
            return false;
        }
        return true;
    }
    public int evalRPN(String[] tokens) {
        Stack<Integer> stack = new Stack<>();
        for(String str : tokens){
           if(isnumber(str)){
            stack.push(Integer.parseInt(str));
            continue;
           }
if(!stack.empty()){
    int res = 0;
    int b = stack.pop();
    int a = stack.pop();
    if(str.equals("+")){
        res = a+b;
    }
    if(str.equals("-")){
        res = a-b;
    }
    if(str.equals("*")){
        res = a*b;
    }
    if(str.equals("/")){
        res = a/b;
    }
    stack.push(res);
}

        }
        return stack.pop();
    }

3. 出栈入栈次序匹配

栈的压入、弹出序列

题目解析:

1).创建一个栈,原来入栈;

2)遍历入栈数组,先入栈,循环判断是否不为空;

3).如果相等,直接出栈,出栈数组往后遍历加1

4).如果不相等,直接结束此次循环;

5).返回栈是否为空

java 复制代码
public boolean IsPopOrder (int[] pushV, int[] popV) {
        // write code here
        Stack<Integer> stack = new Stack<>();
        int sizepushV = 0;
        int sizepopV = 0;
        for(;sizepushV<pushV.length;sizepushV++) {
            stack.push(pushV[sizepushV]);
            while(!stack.empty()){
if(stack.peek()==popV[sizepopV]){
    stack.pop();
    sizepopV++;
}
else{
    break;
}
            }
        }
        return stack.empty();
    }

4. 最小栈

最小栈

可以看到给了一个构造方法用来初始化,然后四个操作方法;

题目解析:

1)首先定义两个栈 ,一个用来正常存储原数据,一个用来存储最小元素的栈

java 复制代码
    public MinStack() {
        private Stack<Integer> stack = new Stack<>();
                private Stack<Integer> minstack = new Stack<>();
    }

2)判断,数值每次存储在satack,如果最小栈为空,存储value;

不断比较min最小值来更新,最后入栈min

java 复制代码
    public void push(int value) {
       stack.push(value);
        if(minstack.empty()){
            minstack.push(value);
            return ;
        }
                int min = minstack.peek();
                if(value<min){
                    min = value;
                }
                else{
                    min = min;
                }
                minstack.push(min);
    }

3)出栈

java 复制代码
  public void pop() {
        stack.pop();
        minstack.pop();
    }
    
    

4)取栈顶元素

java 复制代码
  public int top() {
        return stack.peek();
    }
    
   

5)取最下栈顶元素

java 复制代码
 public int getMin() {
        return minstack.peek();
    }

四.面试题

1. 用队列实现栈。

用队列实现栈

1).首先关键是出栈和去栈;

2).我们需要准备两个队列,一个用来存储元素,当出栈时,将A中的元素不断循环遍历倒腾到B,只剩一个元素就可以出栈了,达到了栈的出栈;

3)取栈顶元素与出栈差不多,只不过多加了一个把最后一个元素还是要倒腾到B中;

java 复制代码
class MyStack {

public Queue<Integer> A = new LinkedList<>();
public Queue<Integer> B = new LinkedList<>();
    public MyStack() {
    }
        public boolean empty(){
        return A.isEmpty()&&B.isEmpty();
    }
    public void swapAB(){
        Queue<Integer> temp = new LinkedList<>();
        temp = A;
        A = B;
        B = temp;
    }
    public void push(int x) {
        A.offer(x);
    }
    public int pop() {
        if(empty()){
            return  0;
        }
        while(A.size()>1){
            Integer cur = A.poll();
            B.offer(cur);
        }
        Integer res = A.poll();
        swapAB();
        return res;
    }
    public int top() {
                if(empty()){
            return  0;
        }
        while(A.size()>1){
            Integer cur = A.poll();
            B.offer(cur);
        }
        Integer res = A.poll();
        B.offer(res);
        swapAB();
        return res;
    }
}

2. 用栈实现队列。

用栈实现队列

题目解析:

1)首先创建两个栈,A用来入队列,B用来出队列;

2)检查B是否为空,如果不为空,首先将B的元素倒腾到A里面去,然后再对A进行入栈操作;

3)出栈时遵循后进先出,依次将A中的元素入到B中,B中采用后进先出,此时就达到队列的作用

相关推荐
花开路口2 小时前
线程安全完全指南:从 Java 到 Kotlin,一文吃透并发编程
java·kotlin
她说..2 小时前
IntelliJ IDEA 快捷键速查表(Mac 版)
java·macos·intellij-idea
EatFan3 小时前
JunoYi 框架实践:Spring Boot 项目为什么拆成 framework、module、server 三层?
java·spring boot·后端·framework·module·模块化·junoyi
Wang's Blog3 小时前
Java 项目实战: 外卖平台优化-从库Slave配置与主从复制验证
java·开发语言
子一!!3 小时前
集成Spring家族的Spring论坛实战==一阶段
java·后端·spring
何中应3 小时前
Maven 执行控制台中文乱码问题
java·maven·intellij-idea
Zhou1411363 小时前
SpringSecurity_01_入门与认证
java
java_nnnn3 小时前
JavaEE进阶-CSS初识
java·前端·css·java-ee·html
Wang's Blog3 小时前
Java 项目实战: 外卖平台优化-使用Redis作为缓存产品与TTL配置
java·redis·缓存