笔试常考: 队列实现栈 and 栈实现队列 and 验证栈序列

文章详细介绍了栈和队列的基本概念,以及在Java中如何使用LinkedList和ArrayDeque实现栈和队列。此外,还探讨了如何用队列和栈来彼此实现,以及解决验证栈序列的问题。重点在于数据结构的高效利用和转换。

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

目录

一.浅谈栈和队列

1.栈

2.队列

二.Java中的栈和队列

1.Java中的栈

2.Java中的队列

3.双端队列

1.LinkedList

 2.ArrayDeque

三.队列来实现栈

1.双队列实现栈

1.问题分析

2.代码实现

2.单队列实现栈

1.问题分析

2.代码实现

四.栈实现队列

1.双栈实现队列

1.问题分析

2.代码实现

五.验证栈序列

1.题目描述

2.问题分析

3.代码实现


一.浅谈栈和队列

1.栈

我们都熟知栈是一种先进后出的数据结构,数据只能从一段进入,从这一段出去

如下图就是抽象的栈结构,数据只能从右端进入,从右端出去,例如只能弹出5(也就是最后插入的元素),要进入6元素,只能在5的后面

2.队列

我们都熟知队列是一种先进后出的数据结构,数据从一段进出,并从另一端出去

如下图就是抽象的队列结构,数据只能从左端出,从右端进入,例如只能先弹出1(也就是最先进入队列的元素),也只能在右端插入新数据6

二.Java中的栈和队列

1.Java中的栈

Java API中有专门的栈的API,如图,但是这个类用来实现栈的效率十分低,因为Vector是一个线程安全的类,因此在具体的使用中,我们不建议创建Stack的对象.推荐的我们放在了第三个:双端队列

2.Java中的队列

Java中没有命名为Queue的类,但是相应的接口,我们不可以直接创建Queue的对象,因为Queue是接口不是类,但是有实现Queue接口的队列,具体看第三个:双端队列

3.双端队列

双端队列虽然叫队列,但他同样也可以实现栈的功能,因此一种API既可以实现栈,也可以实现队列,都有具体的实现方法

我们都知道队列和栈有两种实现的方式,线性表(数组)和链表,同样的双端队列也有两种实现的方式

1.LinkedList

LinkedList底层使用链表来实现的,现在我们来具体介绍一下实现队列和栈的功能的API

LinkedList<Integer> stack = new LinkedList<>();
stack.push(1);
stack.push(2);
stack.push(3);
stack.push(4);
System.out.println(stack);//[4, 3, 2, 1]
System.out.println(stack.pop());//4
System.out.println(stack.peek());//3

从以上方法可以看出,LinkedList的确可以实现栈的功能,只需要使用push和pop方法即可

队列

LinkedList<Integer> queue = new LinkedList<>();
queue.offer(1);
queue.offer(2);
queue.offer(3);
queue.offer(4);
System.out.println(queue);//[1, 2, 3, 4]
System.out.println(queue.poll());//1
System.out.println(queue.peek());//2

 从以上方法可以看出,LinkedList的确可以实现队列的功能,只需要使用offer和poll方法即可

总结: 按我的理解就是当执行offer方法的时候,就是在链表的尾部插入数据,执行push方法的时候,就是在链表的头部插入数据,当执行poll方法的时候,就是在链表的头部删除数据,执行pop方法的时候,就是在链表的尾部删除数据,peek方法就是取出链表头部的数据,我们可以使用peekLast取出链表尾部的数据

 2.ArrayDeque

LinkedList底层使用数组来实现的,现在我们来具体介绍一下实现队列和栈的功能的API

具体方法调用和LinkedList一模一样,只是new对象不同,这里不做更多的介绍

ArrayDeque<Integer> queue = new ArrayDeque<>();

三.队列来实现栈

力扣上专门的题目,在这里可以作参考:力扣

1.双队列实现栈

1.问题分析

我们都知道栈最后入栈的元素最先出栈,而队列最先入栈的元素最后出栈.

用队列来实现栈,我们需要考虑的就是如何将最先入队列的元素置入队列的尾端,最后入队列的元素置入队列的首端(正好符合栈的出栈序列),也就是说原本的{1,2,3,4}顺序,现在需要以{4,3,2,1}顺序存储到队列中.我们可以用双队列来执行

  • 将元素1入队列
  • 将元素2入队列

  • 将元素3入队列

  • 将元素4入队列

 

 以上便可以用双队列达到了栈的效果,但是我们这样每次数据保存的在队列的位置不确定,我们不妨每次将queue1和queue2的引用进行交换,使得每次queue1引用指向的队列就是我们存放数据的队列.

2.代码实现

class MyStack {
    //存储元素的队列
     private LinkedList<Integer> queue1 = new LinkedList<>();
     //辅助队列
     private LinkedList<Integer> queue2 = new LinkedList<>();

    public MyStack() {

    }

    public void push(int x) {
        queue2.offer(x);
        while(!empty()){
         queue2.offer(queue1.pop());   
        }
        LinkedList<Integer> temp=queue1;
        queue1=queue2;
        queue2=temp;
      
    }

    public int pop() {
        if (empty()) {
            return -1;
        }
        return queue1.poll();
    }

    public int top() {
        if (empty()) {
            return -1;
        }
        return queue1.peek();
    }

    public boolean empty() {
        return queue1.isEmpty();
    }

}

2.单队列实现栈

1.问题分析

经历了上面的双队列实现栈,我们其实可以很容易的想到如何使用单队列实现栈的功能,我们只需要每次入队列指定的元素,然后将队列之前的元素重新入队列,便可以实现栈的功能,接下来看演示

  • 将元素1入队列
  • 将元素2入队列
  • 将元素3入队列
  • 将元素4入队列

 

2.代码实现

class MyStack {
    private LinkedList<Integer> queue = new LinkedList<>();
    public MyStack() {

    }
    
    public void push(int x) {
        queue.offer(x);
        int size=queue.size();
        for(int i=0;i<size-1;++i){
            queue.offer(queue.poll());
        }


    }
    
    public int pop() {
        return queue.poll();

    }
    
    public int top() {
       return queue.peek();
    }
    
    public boolean empty() {
       return queue.size()==0;
    }
}

四.栈实现队列

 力扣上专门的题目,在这里可以作参考:力扣

1.双栈实现队列

1.问题分析

可能很多人会想单队列能够实现栈,单栈一定也能够实现队列,其实我们只能用双栈来实现队列,这是因为栈的特殊性,所以我们这里来讨论双栈实现队列的思路

因为队列的先进先出的,所以这里栈一定要把先进的元素放在栈的顶部,这样才能够满足队列的结构,也就是说我们要把栈的结构倒转过来,这时候一定需要另一个栈的辅助,比如入栈的顺序为{1,2,3,4},这个时候放入到栈中的顺序应该为{4,3,2,1},这样出栈的顺序满足出队列的先进先出的原则.接下里我们使用演示的方式看看如何实现这个功能

  • 将元素1入队列
  • 将元素2入队列
  • 将元素3入队列
  • 将元素4入队列

 

2.代码实现

class MyQueue {
    LinkedList<Integer> stack1=new LinkedList<>();
    LinkedList<Integer> stack2=new LinkedList<>();


    public MyQueue() {

    }

    public void push(int x) {
       while(!stack1.isEmpty()){
           stack2.push(stack1.pop());
       }
       stack1.push(x);
       while(!stack2.isEmpty()){
           stack1.push(stack2.pop());
       }

    }

    public int pop() {
        int val=stack1.pop();
        return val;
    }

    public int peek() {        
     return stack1.peek();
    }

    public boolean empty() {
        return stack1.isEmpty();

    }
}

五.验证栈序列

1.题目描述

给定 pushed 和 popped 两个序列,每个序列中的 值都不重复,只有当它们可能是在最初空栈上进行的推入 push 和弹出 pop 操作序列的结果时,返回 true;否则,返回 false 。

力扣:力扣

2.问题分析

对于一个序列,因为我们可以在入栈的同时进栈,所以出栈的可以有多种顺序,例如对A,B,C,D入栈,出栈的顺序不一定是D,C,B,A,因为随时可以出栈,比如入栈一个出栈一个,出栈的顺序就为:A,B,C,D

因此判断是否为栈序列,我们判断栈顶元素是否为popped的元素,如果不是将pushed的元素进行入栈,直到栈顶元素为popped的元素,然后对入栈的pushed元素依次进行出栈,直到栈顶的元素不为popped的出栈序列

3.代码实现

    public boolean validateStackSequences(int[] pushed, int[] popped) {
        LinkedList<Integer> stack = new LinkedList<>();
        int i=0;
        for(int val:pushed){
            stack.push(val);
            while(!stack.isEmpty()&&stack.peek()==popped[i]){
                stack.pop();
                i++;
            }
        }
        return stack.isEmpty();

    }

评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

允歆辰丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值