代码随想录刷题-day10

128 阅读4分钟

栈与队列

理论基础

栈与队列的基本实现相关知识

  • 无论是栈还是队列数据结构,其底层都有可能是通过数组或者链表来实现。我们可以将栈、队列视为一种受限制的数组或链表。

  • 栈——先进后出。 队列——先进先出。

调用Java自带的库来完成栈的基本操作——Stack

 //直接调用Java提供的栈类
            Stack<Integer> stack=new Stack<>();
            //执行入栈操作
            stack.push(1);
            stack.push(2);
            stack.push(3);
            stack.push(4);
            //获取栈顶元素
            System.out.println(stack.peek());
    
            //判断栈是否为空
            System.out.println(stack.isEmpty());
            //获取栈的大小
            System.out.println(stack.size());
            //出栈
            stack.pop();

调用Java自带的库来学习调用队列的操作

    //直接调用Java提供的队列类
            Queue<Integer> queue=new LinkedList<>();
            //入队操作
            queue.offer(1);
            queue.offer(2);
            queue.offer(3);
            queue.offer(4);
            //判断队列是否为空
            queue.isEmpty();
            //出队操作
            queue.poll();
            //遍历队列 —— 使用迭代器
            Iterator<Integer> it=queue.iterator();
            while(it.hasNext()){
                int element=it.next();
                System.out.println(element);
            }
    

这里也稍微复习一下Java中关于多态的知识。Java中与栈Stack不同的是,Queue只是一个接口,而LinkedList是其的一个实现类。

 Queue<Integer> queue=new LinkedList<>();

Queue是一个接口,它定义了一系列用于操作队列的方法,如add()remove()element()poll()peek()等。LinkedList是一个实现了Queue接口的类,因此它提供了这些方法的实现。

Java中多态性主要通过以下两种方式来实现:

  1. 编译时多态:方法重载。在一个类中,可以定义多个同名但是参数列表不同的方法,在调用时,Java编译器会根据调用时提供的参数类型 以及 参数数量 来确定调用哪个方法。
  2. 运行时多态:方法重写。 子类可以重写父类/父接口中的方法,并在运行时根据对象的实际类型来确定调用哪个方法。通常涉及到向上转型(把子类对象赋值给父类引用)和向下转型(把父类引用强制转换为子类引用)。
  • 在这里,通过将LinkedList向上转型为Queue类型,限制了可以通过这个引用来访问的方法——即只能访问Queue接口中定义的方法,而不能访问LinkedList中的特有方法。
 class Animal {  
        void makeSound() {  
            System.out.println("Animal makes a sound");  
        }  
    }  
    
    class Dog extends Animal {  
        @Override  
        void makeSound() {  
            System.out.println("Dog barks");  
        }  
    }  
    
    class Cat extends Animal {  
        @Override  
        void makeSound() {  
            System.out.println("Cat meows");  
        }  
    }  
    
    public class TestPolymorphism {  
        public static void main(String[] args) {  
            Animal myAnimal1 = new Dog();  
            Animal myAnimal2 = new Cat();  
    
            myAnimal1.makeSound(); // 输出 "Dog barks"  
            myAnimal2.makeSound(); // 输出 "Cat meows"  
        }  
    }

232.用栈实现队列

使用栈来实现队列,一定是要使用双栈,如果仅使用一个栈,无法完成队列的操作。

这里两个栈分为stackInput 和 stackOutput

两个关键:

  1. 入队操作:直接入stackInput栈即可

  2. 出队操作:

  3. 如果stackOutput栈中尚有元素,则直接stackOutput.pop()即可

  4. 如果stackOutput栈中没有元素,则要先将stackInput这个栈中的元素一次性全部倒入到stackOutput栈中,然后再stackOutput这个栈pop

具体代码实现:

class MyQueue {
        //使用双栈来实现队列--一个是输入栈,一个是输出栈
        private Stack<Integer> stackInput=new Stack<>();
        private Stack<Integer> stackOutput=new Stack<>();
        public MyQueue() {
    
        }
    
        public void push(int x) {
            stackInput.push(x);
        }
    
        public int pop() {
            //因为在peek()方法中一并判断了输出栈为空和不为空的情况
            //所以这里就直接调用peek()方法即可。
            this.peek();
            return stackOutput.pop();
        }
    
        public int peek() {
            //如果输出栈不为空,则输出栈的栈顶元素即为当前队列首元素
            if(!stackOutput.isEmpty()){
                return stackOutput.peek();
            }
            //由于题目中已经设置了所有操作都是有效的这个前提,故不考虑队列为空的情况
            //如果输出栈为空,此时输入栈不为空.将其元素全部倒入输出栈中。
            while(!stackInput.isEmpty()){
                int num=stackInput.pop();
                stackOutput.push(num);
            }
            return stackOutput.peek();
        }
    
        public boolean empty() {
            //输入输出两个栈都为空,则当前队列为空
            if(stackInput.isEmpty()&&stackOutput.isEmpty()){
                return true;
            }
            else
                return false;
        }
    }
    
    /**
     * Your MyQueue object will be instantiated and called as such:
     * MyQueue obj = new MyQueue();
     * obj.push(x);
     * int param_2 = obj.pop();
     * int param_3 = obj.peek();
     * boolean param_4 = obj.empty();
     */

225. 用队列实现栈

因为队列是先进先出的逻辑,仔细推敲会发现如果继续采用上一题的对策,即一个为input另一个为output的话,顺序丝毫没有改变。

所以两个队列实现栈,一个专门用于存储,另一个就只是备份。


    class MyStack {
        //如之前分析,一个队列用于存储,另一个队列是用于备份存储
        //这里queue1一直用于存储,queue2始终用于备份
        private Queue<Integer> queue1=new LinkedList<>();
        private Queue<Integer> queue2=new LinkedList<>();
        public MyStack() {
    
        }
        public void push(int x) {
            //保证每次push的时候,queue1中的顺序都要和真实的栈中的顺序一致
            //所以先存入到辅助队列queue2中
            queue2.offer(x);
            //就是在这里实现了队列中元素的顺序和真实的栈保持一致
            while(!queue1.isEmpty()){
                queue2.offer(queue1.poll());
            }
            //两个队列交换
            Queue<Integer> temp=queue1;
            queue1=queue2;
            queue2=temp;
            
        }
        
        public int pop() {
            return queue1.poll();
        }
        
        public int top() {
            return queue1.peek();
        }
        public boolean empty() {
            return queue1.isEmpty();
        }
    
    }
    
    /**
     * Your MyStack object will be instantiated and called as such:
     * MyStack obj = new MyStack();
     * obj.push(x);
     * int param_2 = obj.pop();
     * int param_3 = obj.top();
     * boolean param_4 = obj.empty();
     */