数据结构之队列

队列(Queue)

今天给大家带来的是一篇关于数据结构中队列的知识,主要讲解了队列,以及其相关api和队列的简单实现,以及三道经典的OJ题,包括用队列实现栈、用栈实现队列、实现一个最小栈。
话不多说,我们直接进入正题!

队列概念

队列是我们常见的一种数据结构,它只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表。队列具有先进先出的特点,根据其元素的进出位置,将其分为:
入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端成为队头
队列的具体表现如图所示:
在这里插入图片描述
对于队列说在集合框架中是一个接口,但是从如下的图可以看出,队列的底层实现是一个双向链表来进行实现的。
在这里插入图片描述
因此我们就采用双向链表对于队列的关键API进行模拟实现

模拟实现队列

对于队列其实现的关键API参数如下:

API实现的功能
boolean offer(E e)入队列
E poll()出队列
peek()获取队头元素
int size()获取队列中有效元素个数
boolean isEmpty()检测队列是否为空

实现的代码如下:

public class MyQueue2<E>{
    //使用双向链表作为底层实现的原理
    public static class ListNode<E>{
        ListNode<E> next;
        ListNode<E> prev;
        E value;

        ListNode(E value){
            this.value=value;
        }
    }
    ListNode<E> first;
    ListNode<E> last;
    int size=0;
    //入队列为队尾  出队列为队头
    public void offer(E e){
        ListNode<E> newNode=new ListNode<>(e);
        if (first==null){
            first=newNode;
        }else {
            last.next=newNode;
            newNode.prev=last;
        }
        last=newNode;
        size++;
    }
    public E poll(){
        //判断队列是否为空
        //队列中只有一个元素
        //队列中有多个元素
        E value=null;
        if (first==null){
            return null;
        }else if (first==last){
            value=first.value;
            last=null;
            first=null;
        }else {
            //有其他的节点
            value=first.value;
            first=first.next;
            //前一个节点的下一个下标地址为空
            first.prev.next=null;
            //指向前一个的地址为空
            first.prev=null;
        }
        size--;
      return value;
    }
    //获取队列的头元素
    public E peek(){
        if (first==null){
            return null;
        }
        return first.value;
    }
    //长度
    public int size(){
        return size;
    }
    public boolean isEmpty(){
        return first==null;
    }
    @Override
    public String toString() {
       String s="[";
       ListNode<E> cur=first;
      while (cur!=null){
          if (cur.next!=null){
          s+=cur.value+" ";
          }else {
              s+=cur.value;
          }
          cur=cur.next;
      }
       s+="]";
       return s;
    }
    public static void main(String[] args) {
        MyQueue2<Integer> myQueue2=new MyQueue2<>();
        myQueue2.offer(1);
        myQueue2.offer(2);
        myQueue2.offer(3);
        myQueue2.offer(4);
        myQueue2.offer(5);
        myQueue2.offer(6);
        myQueue2.offer(7);
        myQueue2.offer(8);
        myQueue2.offer(9);
        System.out.println(myQueue2);
        int m=myQueue2.poll();
        System.out.println(m);
        System.out.println(myQueue2);
        System.out.println(myQueue2.size());
        System.out.println(myQueue2.peek());
        System.out.println(myQueue2.isEmpty());
    }
}
队列的相关OJ题
模拟实现循环队列

循环队列

具体要求:
MyCircularQueue(k): 构造器,设置队列长度为 k 。
Front: 从队首获取元素。如果队列为空,返回 -1 。
Rear: 获取队尾元素。如果队列为空,返回 -1 。
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
isEmpty(): 检查循环队列是否为空。
isFull(): 检查循环队列是否已满

实现分析:
构造器:根据输入的长度来实现构造即可
获取队首元素:调用方法判断是否为空,直接输出数组的第一个元素即可
获取队尾元素:调用方法判断是否为空,输出数组的第一个元素,此时需要判断是否是数组存在越界的情况,利用循环下标的方式将数组的元素进行获取输出。
向循环链队列插入一个元素:调用方法判断队列是否是一个满的状态,如果是不满的状态就向队尾进行插入,同时将插入的数据数量进行加一的操作。最后判断插入后的长度是否等于构建的长度,如果等于将最后一个元素重新赋值为0,
向循环链队列删除一个元素:调用方法判断队列是否为空,如果不为空则就进行将删除操作,同时下标向后移动,但是需要判断是否是下标越界的情况。
检查循环队列是否为空:通过计数来判断
检查循环队列是否已满:通过计数和构造的长度是否一样来判断
实现的代码如下:

//循环队列
public class MyCircularQueue {
    //利用循环数组下标来进行实现该操作
    int[] array; //循环队列的容器
    int first=0; //循环队列开始的地方
    int end=0;//末尾的地方
    int n; //表示循环队列的长度
    int size=0;

    public MyCircularQueue(int k) {
           array=new int[k];
           n=k;
    }
    //插入元素,如果成功插入则返回真
    public boolean enQueue(int value) {
      if (isFull()){
          return false;
      }
      //从队尾进入队列中
      array[end]=value;
      end++;
      size++;
      if (end==n){
          end=0;
      }
      return true;
    }

    public boolean deQueue() {
       if (isEmpty()){
           return false;
       }
       first++;
       //防止在出对队列的时候崩溃
       first%=n;
       size--;
       return true;
    }
    //获取队头元素
    public int Front() {
    if (isEmpty()){
        return -1;
    }
    return array[first];
    }
    //获取队尾元素
    public int Rear() {
       if (isEmpty()){
           return -1;
       }
       //防止产生数组越界的情况
       return array[(end-1+n)%n];
    }
    //是否为空
    public boolean isEmpty() {
      return size==0;
    }
    //是否已满
    public boolean isFull() {
        //通过长度来进行判断
     return size==array.length;
    }
}

用队列实现栈的操作

用队列实现栈的操作

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

实现思路:将最新插入的元素放在一个空队列中,然后将之前的元素更新到当前的队列中,就可保证在当前的队列出来的元素满足后进先出(栈的特性)。
具体实现代码:

class MyStack {
     public Queue<Integer> q1;
     public Queue<Integer> q2;
     public MyStack() {
      q1=new  LinkedList<>();
      q2=new LinkedList<>();
    }
    public void push(int x) {
      //用一个来接收
        q1.offer(x);
     //用将当前的这个数据存放在q2中 保证q1始终为空
        while (!q2.isEmpty()) {
            q1.offer(q2.poll());
        }
            //现在所有的元素存放在q1当中 q1和q2进行交换
            Queue tmp=q1;
            q1=q2;
            q2=tmp;
            //此时q2中为所有的元素,且q1为空 q2的队头元素为最新插入的元素。
    }
 //出队列
    public int pop() {
    return q2.poll();
    }
    public int top() {
    return q2.peek();
    }
    public boolean empty() {
     return q2.isEmpty();
    }
}
用栈来实现队列

用栈实现队列

要求:
实现 MyQueue 类:
void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false

解题思路:
用一个栈来获取插入的元素,然后将当前栈的元素放入到另一个栈中,实现队列的插入。在取出队列的元素时,需要保证队列的元素顺序,从有元素的栈取出后,栈的元素就是最先放入的元素,此时将其取出,然后将栈的元素重新放入空栈中,保证栈内的顺序一致。最后判断一个有元素的栈是否为空来判断队列是否为空。

class MyQueue {
 //队列先进先出  栈是先进后出   将数据放在不为空的栈当中即可
    public Stack<Integer> s1;
    public Stack<Integer> s2;
    public MyQueue() {
      s1=new Stack<>();
      s2=new Stack<>();
    }
    public void push(int x) {
       //元素统一放在一个栈中  插入后进行从当前栈取出 放入空的栈中  最后交换
       s1.push(x);
       s2.push(s1.pop());
       //现在s2栈是满的  s1为空
    }

    public int pop() {
        while (!s2.isEmpty()){
            //交换元素的出栈顺序
            s1.push(s2.pop());
        }
        //获取最早的栈元素
        int ret=s1.pop();
        //重现调整放入顺序
        while (!s1.isEmpty()){
            s2.push(s1.pop());
        }
        //取出最早的元素
      return ret;
    }

    public int peek() {
        while (!s2.isEmpty()){
            //交换元素的出栈顺序
            s1.push(s2.pop());
        }
        //获取最早的栈元素
        int ret=s1.peek();
        //重现调整放入顺序
        while (!s1.isEmpty()){
            s2.push(s1.pop());
        }
        //取出最早的元素
        return ret;
    }

    public boolean empty() {
     return s2.isEmpty();
    }
}
最小栈的实现

最小栈

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

实现 MinStack 类:
MinStack() 初始化堆栈对象。
void push(int val) 将元素val推入堆栈。
void pop() 删除堆栈顶部的元素。
int top() 获取堆栈顶部的元素。
int getMin() 获取堆栈中的最小元素。

解题思路:
用一个栈来存储数据,另一个栈来存储最小的数据,最后更新和输出最小的数据即可。

实现代码:

public class MyMinStack {
    public  Stack<Integer> s1;
    public  Stack<Integer> s2;
    public MyMinStack() {
       s1=new Stack<>();
       s2=new Stack<>();
    }
    public void push(int val) {
        if(s2.empty() || val <= s2.peek()){
            s2.push(val);
        }

        s1.push(val);
    }

    public void pop() {
        if(s1.peek() == s2.peek()){
            s2.pop();
        }

        s1.pop();
    }

    public int top() {
        return s1.peek();
    }

    public int getMin() {
        return s2.peek();
    }
  }

以上就是今天队列相关的知识了。谢谢大家的关注!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值