数据结构——队列Queue

队列 :只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out) 入队列:进行插入操作的一端称为 队尾( Tail/Rear 出队列:进行删除操作的一端称为 队头( Head/Front ) 。
简单说:就像去食堂排队,排在队尾,打完饭从队头出。先进先出的模式。

 

队列的所有方法

 

运用offer(),poll(),peek()方法 。接收类型都与尖括号里的类型参数一至,E类型代表返回值,也与尖括号里类型参数一至。

 

运行结果

 官方给出的Queue方法

 

分成三组来看,每组方法是差不多的用法,我们更倾向于用右边这三个方法

如:第一组add方法如果容量受限就会抛异常。offer在容量受限的情况不抛异常。(用offer方法较多一点)

 

LinkedList<Integer> queue = new LinkedList<>();这一种使用的方法更多,可以用LinkedList的方法

Queue<Integer> queue = new LinkedList<>();这种只能用Queue的方法

LinkedList之所以方法很多是因为不仅实现了Queue接口还实现了Deque接口,Deque是一个双端队列。

所以LinkedList这个集合类功能很多 可以 当队列 当链表(可以是双向链表,也可以是单链表)当栈。


问:用单链表 实现队列,问入队采用 头插 还是 尾插?

答:双链表 出队 入队时间复杂度都是O(1)。单链表 用尾插法实现队列,尾巴入时间复杂度O(n),头出时间复杂度O(1)。


 22. 设计循环队列  

力扣

难度中等

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

你的实现应该支持如下操作:

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

示例:

MyCircularQueue circularQueue = new MyCircularQueue(3); // 设置长度为 3
circularQueue.enQueue(1);  // 返回 true
circularQueue.enQueue(2);  // 返回 true
circularQueue.enQueue(3);  // 返回 true
circularQueue.enQueue(4);  // 返回 false,队列已满
circularQueue.Rear();  // 返回 3
circularQueue.isFull();  // 返回 true
circularQueue.deQueue();  // 返回 true
circularQueue.enQueue(4);  // 返回 true
circularQueue.Rear();  // 返回 4

思路

 这是一个模型

从rear入队,从front出队。初始的时候让rear 和 front都指向0下标。rear在0下标插入元素的时候自己走在1下标,rear插入元素的时候始终站在空的格子上。

 法2:也可以用usedsize ==length来判断是不是满了

class MyCircularQueue {
    private int[] elem;
    private int front;//表示队头下标
    private int rear;//表示队尾下标
    /**
     * 构造方法
     * @param k K个大小
     */
    public MyCircularQueue(int k) {
        elem = new int[k+1];//这里一定要让k加1
               //让原本数组个数加一个空的位置
    }

    /**
     * 入队
     * 1、判断是不是满的?
     * 2、把当前需要存放的元素放到rear下标的地方。
     * @param value
     * @return
     */
    public boolean enQueue(int value) {
        if(isFull()) {
            return false;
        }
        this.elem[rear] = value;
        //注意这里 不要出错!不要让rear++;如果在最后位置要走到0位置,++就不对。
        rear = (rear+1) % elem.length;
        return true;
    }

    /**
     * 出队
     * @return
     */
    public boolean deQueue() {
        if(isEmpty()) {
            return false;
        }
        front = (front+1) % elem.length;
        return true;
    }

    /**
     * 得到队头元素
     * @return
     */
    public int Front() {
        if(isEmpty()) {
            return -1;
        }
        return elem[front];
    }

    /**
     * 得到队尾元素
     * @return
     */
    public int Rear() {
        if(isEmpty()) {
            return -1;
        }
        int index = (rear == 0) ? (elem.length-1) : (rear-1);
        return elem[index];
    }

    /**
     * 当前循环队列是否为空
     * @return
     */
    public boolean isEmpty() {
        return rear == front;
    }

    /**
     * 判断当前队列是否为满
     * 浪费一个空间来表示满
     * @return
     */
    public boolean isFull() {
        if( (rear+1)%elem.length == front ) {
            return true;
        }
        return false;
    }
}

 

225. 用队列实现栈

难度简单

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppop 和 empty)。

实现 MyStack 类:

  • void push(int x) 将元素 x 压入栈顶。
  • int pop() 移除并返回栈顶元素。
  • int top() 返回栈顶元素。
  • boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
  • 输入:
    ["MyStack", "push", "push", "top", "pop", "empty"]
    [[], [1], [2], [], [], []]
    输出:
    [null, null, null, 2, 2, false]

    解释:
    MyStack myStack = new MyStack();
    myStack.push(1);
    myStack.push(2);
    myStack.top(); // 返回 2
    myStack.pop(); // 返回 2
    myStack.empty(); // 返回 False

    来源:力扣(LeetCode)
     

思路:

题意给两个队列,要做到有栈的功能。

如图给定qu1,qu2两个队列。队列的特点是 先进先出(像是生活中排队)。栈的特点是 先进后出。

1.先把给的一组元素存到一个队列里。2.根据队列先进先出,把存进队列的元素 出队列 到另一个队列,但是留出最后一个元素(图中的45)接收给他出队列。

这样就做到了栈的功能:先进后出。

class MyStack {

    private Queue<Integer> qu1;
    private Queue<Integer> qu2;

    public MyStack() {
        qu1 = new LinkedList<>();
        qu2 = new LinkedList<>();
    }
    
    /**
    入到不为空的队列当中
    如果都为空 放到qu1当中
     */
    public void push(int x) {
        if(!qu1.isEmpty()) {
            qu1.offer(x);
        }else if(!qu2.isEmpty()) {
            qu2.offer(x);
        }else{
            qu1.offer(x);
        }
    }
    
    public int pop() {
        //1、先要判断 当前 “栈” 是否为空
        if(empty()) {
            return -1;
        }

        if(!qu1.isEmpty()) {
            //出这个不为空的队列,最后一个元素最终保存在tmp
             //q1的size一直在变,所以拿到前面算
            int size = qu1.size();
            for(int i = 0;i < size-1;i++) {
                // int tmp = qu1.poll();
                // qu2.offer(tmp);
                qu2.offer(qu1.poll());
            }
            return qu1.poll();
        } else {
            //出这个不为空的队列,出size-1
            int size = qu2.size();
            for(int i = 0;i < size-1;i++) {
                qu1.offer(qu2.poll());
            }
            return qu2.poll();
        }
    }
    
    public int top() {
        //1、先要判断 当前 “栈” 是否为空
        if(empty()) {
            return -1;
        }

        if(!qu1.isEmpty()) {
            int size = qu1.size();
            int tmp = -1;
            for(int i = 0;i < size;i++) {
                 tmp = qu1.poll();
                 qu2.offer(tmp);
            }
            return tmp;
        } else {
            int size = qu2.size();
            int tmp = -1;
            for(int i = 0;i < size ;i++) {
                tmp = qu2.poll();
                qu1.offer(tmp);
            }
            return tmp;
        }
    }
    
    public boolean empty() {
        if(qu1.isEmpty() && qu2.isEmpty()) {
            return true;
        }
        return false;
    }
}

 

232. 用栈实现队列

难度简单

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

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

说明:

你 只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

来源:力扣(LeetCode)

示例 1:

输入:
["MyQueue", "push", "push", "peek", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]

来源:力扣(LeetCode)
 

思路:1.入队的时候放到第一个栈当中。2.出队的时候出第二个栈当中的。如果第二个栈里面没有元素,那就把第一个栈里面的都倒过来。

    

 import java.util.Stack;

class MyQueue {
  private Stack<Integer> s1;
    private Stack<Integer> s2;

    public MyQueue() {
        s1 = new Stack<>();
        s2 = new Stack<>();
    }
    
    //入队的逻辑:把元素都统一放到第一个栈当中
    public void push(int x) {
        s1.push(x);
    }
    
    //如果第二个栈不为空,则出栈顶元素。否则,将第一个栈的元素全部导入第2个栈
    public int pop() {
        //两个栈都为是空的
        if(empty()) {
            return -1;
        }
        if(s2.empty()) {
            //那么就把s1里面的数据全部导过来
            while(!s1.empty()) {
                s2.push(s1.pop());
            }
        }
        //s2一定是不为空的
        return s2.pop();
    }
    
    public int peek() {
         //两个栈都为是空的
        if(empty()) {
            return -1;
        }
        if(s2.empty()) {
            //那么就把s1里面的数据全部导过来
            while(!s1.empty()) {
                s2.push(s1.pop());
            }
        }
        //s2一定是不为空的
        return s2.peek();
    }
    
    public boolean empty() {
        return s1.empty() && s2.empty();
    }
}

 

155. 最小栈

难度中等

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

实现 MinStack 类:

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

示例 1:

输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]

输出:
[null,null,null,null,-3,null,0,-2]

解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.getMin();   --> 返回 -2.

 题意是用O(1)时间复杂度,就能知道最小值是几。

 

 入栈的时候要和minStack比较,出栈也要和minStack比较。

 

 import java.util.Stack;

class MinStack {
 private Stack<Integer> s1;
    private Stack<Integer> minStack;

    public MinStack() {
        s1 = new Stack<>();
        minStack = new Stack<>();
    }
    
    /**
    s1这个栈 一定要放元素的
     */
    public void push(int val) {
        s1.push(val);
        if(minStack.empty()) {
            minStack.push(val);
        }else{
            int x = minStack.peek();
            //这里一定要取等号
            if(val <= x) {
                minStack.push(val);
            }
        }
    }
    
    public void pop() {
        int x = s1.pop();
        int x2 = minStack.peek();
        if(x == x2) {
            minStack.pop();
        }
    }
    
    //获取当前的栈顶元素不删除 ,不是最小栈的栈顶元素
    public int top() {
        return s1.peek();
    }
    
    public int getMin() {
        return minStack.peek();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值