栈和队列(栈和队列的那些事)

本文详细介绍了栈和队列的概念,以及它们在Java中的实现。通过实例展示了如何使用Stack和LinkedList创建栈和队列,并提供了手动实现泛型版本的栈和队列的代码。此外,还探讨了如何利用栈和队列解决常见面试问题,如用队列实现栈和用栈实现队列。这些内容有助于深入理解数据结构及其实际运用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.栈

1.1概念

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
原理图:
在这里插入图片描述

1.2java中的栈(Stack)

常用的方法:
在这里插入图片描述

1.3通过代码来感受一下


import java.util.Stack;

public class Test0530 {
    public static void main(String[] args) {
        Stack<Integer> stack=new Stack<>();
        System.out.println("入栈元素1");
        stack.push(1);
        System.out.println("查看栈顶元素"+stack.peek());
        System.out.println("出栈");
        stack.pop();
        System.out.println("看栈是否为空"+stack.empty());

    }
}

运行结果:
在这里插入图片描述

2.手动实现一个自己的栈(MyStack)

手动实现一个泛型版本的栈,可以用存储任意类型的数据:


public class MyStack<T> {
    private T[] arr=null;
    private int size;
    private int capacity=5;

    public MyStack() {
        arr= (T[]) new Object[capacity];
        this.size=0;
    }
    //入栈
    public void push(T var){
        if(size==capacity){ //判断栈是否满了
            //栈满了就扩容
           T[] newarr= (T[]) new Object[2*capacity];
            for(int i=0;i<size;i++){
                newarr[i]=arr[i];
            }
            arr=newarr;
            arr[size++]=var;
            return;
        }
        arr[size++]=var;
        return;
    }
    //出栈
    public void pop(){
        if(empty()){ //空栈
            return;
        }
        size--;
        return;

    }
    //查看栈顶元素
    public T peek(){
        if(empty()){
            return null;
        }
        return (T)arr[size-1];

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

    public static void main(String[] args) {
        MyStack<Integer> myStack=new MyStack<>();
        System.out.println(myStack.empty());
        myStack.push(1); //入栈
        myStack.push(2);
        myStack.push(3);
        myStack.push(4);
        myStack.push(5);
        myStack.push(6); //触发扩容
        myStack.pop();
        myStack.pop();
        Integer result = myStack.peek();
        System.out.println(result);
        System.out.println(myStack.empty());

        System.out.println("============");
        MyStack<String> myStack1=new MyStack<>();
        System.out.println(myStack1.empty());
        myStack1.push("C++");
        myStack1.push("java");
        myStack1.push("Go");
        System.out.println(myStack1.peek());
    }
}

运行结果:
在这里插入图片描述

3.队列

3.1概念

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)。
原理图:
在这里插入图片描述

3.2java中队列(Queue)

常用的方法:
在这里插入图片描述

3.3通过代码来感受一下


import java.util.LinkedList;
import java.util.Queue;
public class Test0530 {
    public static void main(String[] args) {
        Queue<Integer> queue=new LinkedList<>();
        queue.add(1);
        queue.offer(2);

        System.out.println(queue.element());
        System.out.println(queue.peek());
        queue.poll();
        queue.remove();

        System.out.println(queue.isEmpty());

    }
}

运行结果:
在这里插入图片描述

4.手动实现一个自己的队列( MyQueue)

手动实现一个泛型版本的队列,可以用存储任意类型的数据:


class MyExciption extends RuntimeException{
    public MyExciption(String msg) {
        super(msg);
    }
}

class Node<T>{
    T var;
    Node<T> pre;
    Node<T> next;

    public Node(T var) {
        this.var = var;
    }

    @Override
    public String toString() {
        return "Node{" +
                "var=" + var +
                '}';
    }
}

public class MyQueue<T> {
    private Node<T> head;
    private Node<T> tail;
    private int size;

    public MyQueue() {
        this.head = null;
        this.tail = null;
        this.size = 0;
    }
    //入队列  1  2   3
    public void offer(T var){
        Node<T> newNode=new Node<>(var);
        if(head==null){
            head=newNode;
            tail=newNode;
            size++;
            return;
        }
        //一般情况 1 2 3
        tail.next=newNode;
        newNode.pre=tail;
        tail=newNode;
        size++;
        return;

    }
    //入队列
    public void add(T var){
        Node<T> newNode=new Node<>(var);
        if(head==null){
            head=newNode;
            tail=newNode;
            size++;
            return;
        }
        //一般情况 1 2 3
        tail.next=newNode;
        newNode.pre=tail;
        tail=newNode;
        size++;
        return;

    }
    //出队列
    public void poll(){
        if(head==null){
            return ;
        }
        if(head.next==null){
            head=null;
            tail=null;
            size--;
            return;
        }
        //一般情况 1   2   3
        Node<T> curNode=head;
        Node<T> nextNode=curNode.next;
        nextNode.pre=null;
        head=nextNode;
        size--;
        return;

    }
    //出队列
    public void remove(){
        if(head==null){
            throw new MyExciption("位置非法!!!");
        }
        if(head.next==null){
            head=null;
            tail=null;
            size--;
            return;
        }
        //一般情况 1  2  3
        Node<T> curNode=head;
        Node<T> nextNode=curNode.next;
        nextNode.pre=null;
        head=nextNode;
        size--;
        return;

    }
    //判断是否为空队列
    public boolean isEmpty(){
        return size<=0;

    }
    //取队首元素
    public T peek(){
        if(head==null){
            return null;
        }
        return (T)head;
    }
    //取队首元素
    public T element(){
        if(head==null){
            throw new MyExciption("空指针异常!!!");
        }
        return (T)head;
    }

    public static void main(String[] args) {
        MyQueue<Integer> myQueue=new MyQueue<>();
        myQueue.add(1);
        myQueue.add(2);
        myQueue.offer(3);
        System.out.println(myQueue.peek());
        myQueue.poll();
        System.out.println(myQueue.element());
        System.out.println(myQueue.isEmpty());

    }
}

5.栈和队列常见的笔试题

1:用队列实现栈==>https://leetcode-cn.com/problems/implement-stack-using-queues/


//用两个队列实现一个栈

class MyStack {

    private Queue<Integer> A = new LinkedList<>();
    private Queue<Integer> B = new LinkedList<>();

    /** Initialize your data structure here. */
    public MyStack() {

    }

    /** Push element x onto stack. */
    public void push(int x) {
        // 入栈的时候, 就直接往 A 中插入
        A.offer(x);
    }

    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
        // 出栈的时候, 把 A 中的元素往 B 中倒腾. 当 A 中只剩一个元素的时候,
        // 最后这个元素就是被删除的元素
        if (A.isEmpty() && B.isEmpty()) {
            // 针对空栈的判定. 但是人家给的方法不是 Integer, 没法返回 null, 只能随便返回个值了
            // 在线 OJ 的代码咱们不要抛出异常!!!
            return 0;
        }
        while (A.size() > 1) {
            int tmp = A.poll();
            B.offer(tmp);
        }
        // 当上面的循环结束, 此时 A 中就只剩一个元素了.
        // 把这个最后的元素就作为出栈的结果即可.
        int ret = A.poll();
        // 最终完成操作之后, 要交换 A 和 B 的身份. 保证下次入栈的时候, 还是往 A 中插入.
        swapAB();
        return ret;
    }

    private void swapAB() {
        Queue<Integer> tmp = A;
        A = B;
        B = tmp;
    }

    /** Get the top element. */
    public int top() {
        // 取栈顶元素和出栈类似. 唯一的区别就是, 出栈操作是把 A 的最后一个元素给删了.
        // 取栈顶元素操作是把 A 的最后一个元素还要再塞回到 B 中.
        // 出栈的时候, 把 A 中的元素往 B 中倒腾. 当 A 中只剩一个元素的时候,
        // 最后这个元素就是被删除的元素
        if (A.isEmpty() && B.isEmpty()) {
            // 针对空栈的判定. 但是人家给的方法不是 Integer, 没法返回 null, 只能随便返回个值了
            // 在线 OJ 的代码咱们不要抛出异常!!!
            return 0;
        }
        while (A.size() > 1) {
            int tmp = A.poll();
            B.offer(tmp);
        }
        // 当上面的循环结束, 此时 A 中就只剩一个元素了.
        // 把这个最后的元素就作为出栈的结果即可.
        int ret = A.poll();

        // 这个操作是唯一的区别.
        B.offer(ret);

        // 最终完成操作之后, 要交换 A 和 B 的身份. 保证下次入栈的时候, 还是往 A 中插入.
        swapAB();
        return ret;
    }

    /** Returns whether the stack is empty. */
    public boolean empty() {
        return A.isEmpty() && B.isEmpty();
    }
}

2:用栈实现队列==>https://leetcode-cn.com/problems/implement-queue-using-stacks/


class MyQueue {
    Stack<Integer> A = new Stack<>();
    Stack<Integer> B = new Stack<>();

    /** Initialize your data structure here. */
    public MyQueue() {

    }

    /** Push element x to the back of queue. */
    public void push(int x) {
        // 入队列的时候, 需要先把 B 中的元素都倒腾到 A 中, 再往 A 中插入新元素
        while (!B.isEmpty()) {
            int tmp = B.pop();
            A.push(tmp);
        }
        A.push(x);
    }

    /** Removes the element from in front of queue and returns that element. */
    public int pop() {
        if (A.isEmpty() && B.isEmpty()) {
            return 0;
        }
        // 先把 A 的所有元素都倒腾到 B 中, 然后再通过 B 进行 pop
        while (!A.isEmpty()) {
            int tmp = A.pop();
            B.push(tmp);
        }
        // 删除 B 中的元素
        return B.pop();
    }

    /** Get the front element. */
    public int peek() {
        if (A.isEmpty() && B.isEmpty()) {
            return 0;
        }
        while (!A.isEmpty()) {
            int tmp = A.pop();
            B.push(tmp);
        }
        // 删除 B 中的元素
        return B.peek();
    }

    /** Returns whether the queue is empty. */
    public boolean empty() {
        return A.isEmpty() && B.isEmpty();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值