实现一个队列,其中push_rear(),pop_front()和get_min()都是常量时间操作

时间:2011-01-26 06:54:32

标签: algorithm data-structures queue big-o

我遇到了这个问题: 实现一个队列,其中push_rear(),pop_front()和get_min()都是常量时间操作。

我最初想过使用一个min_ heap数据结构,它对于get_min()具有O(1)复杂度。但是push_rear()和pop_front()将是O(log(n))。

有谁知道实现这样一个有O(1)push(),pop()和min()的队列的最佳方法是什么?

我搜索了这个,并想指出这个Algorithm Geeks thread。但似乎没有一个解决方案遵循所有3种方法的恒定时间规则:push(),pop()和min()。

感谢所有建议。

12 个答案:

答案 0 :(得分:93)

您可以使用O(1)pop(),push()和get_min()实现堆栈:只需将当前最小值与每个元素一起存储。因此,例如,堆栈[4,2,5,1](顶部为1)变为[(4,4), (2,2), (5,2), (1,1)]

然后你可以use two stacks to implement the queue。推到一个堆栈,从另一个堆栈弹出;如果第二个堆栈在弹出期间为空,则将所有元素从第一个堆栈移动到第二个堆栈。

对于pop请求,移动第一个堆栈[(4,4), (2,2), (5,2), (1,1)]中的所有元素,第二个堆栈将是[(1,1), (5,1), (2,1), (4,1)]。现在返回第二个堆栈的顶部元素。

要查找队列的最小元素,请查看各个最小堆栈的最小两个元素,然后取这两个值中的最小值。 (当然,这里有一些额外的逻辑,其中一个堆栈是空的,但这并不难解决。)

它将具有O(1)get_min()push()并且摊销O(1)pop()

答案 1 :(得分:25)

好的 - 我想我有一个答案可以在分摊 O(1)中为你提供所有这些操作,这意味着任何一个操作都可以占用O(n),但任何序列都可以n操作每次操作花费O(1)时间

我们的想法是将您的数据存储为Cartesian tree。这是一个遵循min-heap属性的二叉树(每个节点都不比它的子节点大),并且以一种方式排序,使得节点的顺序遍历可以按照添加它们的相同顺序返回节点。例如,这是序列2 1 4 3 5的笛卡尔树:

       1
     /   \
    2      3
          / \
         4   5

可以使用以下步骤在O(1)摊销时间内将元素插入笛卡尔树。查看树的右侧脊柱(从根部到最右边的叶子的路径始终向右走)。从最右边的节点开始,沿着这条路径向上扫描,直到找到小于你要插入的节点的第一个节点为止 更改该节点以使其右子节点成为此新节点,然后将该节点的前右子节点设置为刚刚添加的节点的左子节点。例如,假设我们要在上面的树中插入另一个2的副本。我们沿着右边的脊柱走过5和3,但是在1以下停在1以下。 2.然后我们将树更改为:

       1
     /   \
    2      2
          /
         3
        / \
       4   5

请注意,inorder遍历给出2 1 4 3 5 2,这是我们添加值的顺序。

这在分摊的O(1)中运行,因为我们可以创建一个等于树的右脊柱中的节点数的潜在函数。插入节点所需的实际时间是1加上我们考虑的脊柱中的节点数(称为k)。一旦我们找到插入节点的位置,脊柱的大小就会缩短k-1,因为我们访问的每个k节点都不再位于右侧脊柱上,并且新节点就在其位置。对于摊销的O(1)插入物,这给出了1 + k +(1-k)= 2 = O(1)的摊销成本。作为另一种思考方式,一旦节点从右侧脊柱移开,它就不再是右侧脊柱的一部分,因此我们将永远不必再次移动它。由于n个节点中的每个节点最多可以移动一次,这意味着n次插入最多可以进行n次移动,因此对于每个元素的摊销O(1),总运行时间最多为O(n)。

要执行出列步骤,我们只需从笛卡尔树中删除最左边的节点。如果这个节点是叶子,我们就完成了。否则,节点只能有一个子节点(右子节点),因此我们用其右子节点替换节点。如果我们跟踪最左边节点的位置,则此步骤需要O(1)时间。但是,在删除最左边的节点并将其替换为右子节点后,我们可能不知道新的最左边节点在哪里。为了解决这个问题,我们只需从树的左侧脊柱向下走,从刚刚移动到最左边的子节点的新节点开始。我声称这仍然在O(1)摊销时间内运行。为了看到这一点,我声称在这些遍历中的任何一个期间最多访问一个节点以找到最左边的节点。要看到这一点,请注意,一旦以这种方式访问​​节点,我们再次查看它的唯一方法是将它从最左边节点的子节点移动到最左边的节点。但访问的所有节点都是最左边节点的父节点,因此不会发生这种情况。因此,在此过程中每个节点最多访问一次,并且pop在O(1)中运行。

我们可以在O(1)中做find-min,因为笛卡尔树让我们可以免费访问树中最小的元素;它是树的根。

最后,要查看节点以与插入它们相同的顺序返回,请注意笛卡尔树始终存储其元素,以便按顺序遍历以排序顺序访问它们。因为我们总是在每一步删除最左边的节点,这是inorder遍历的第一个元素,所以我们总是按照它们插入的顺序返回节点。

简而言之,我们得到O(1)摊销的推送和流行,以及O(1)最坏情况的发现 - 。

如果我能提出最坏情况的O(1)实现,我肯定会发布它。这是一个很大的问题;谢谢发布它!

答案 2 :(得分:21)

好的,这是一个解决方案。

首先我们需要一些在0(1)中提供push_back(),push_front(),pop_back()和pop_front()的东西。使用数组和2个迭代器很容易实现。第一个迭代器将指向前,后到后。我们称之为deque。

这是伪代码:

class MyQueue//Our data structure
{
    deque D;//We need 2 deque objects
    deque Min;

    push(element)//pushing element to MyQueue
    {
        D.push_back(element);
        while(Min.is_not_empty() and Min.back()>element)
             Min.pop_back();
        Min.push_back(element);
    }
    pop()//poping MyQueue
    {
         if(Min.front()==D.front() )
            Min.pop_front();
         D.pop_front();
    }

    min()
    {
         return Min.front();
    }
}

<强>解释

示例让我们推送数字[12,5,10,7,11,19]和我们的MyQueue

1)推12

D [12]
Min[12]

2)推5

D[12,5]
Min[5] //5>12 so 12 removed

3)推动10

D[12,5,10]
Min[5,10]

4)推7 <​​/ p>

D[12,5,10,7]
Min[5,7]

6)推11

D[12,5,10,7,11]
Min[5,7,11]

7)推动19

D[12,5,10,7,11,19]
Min[5,7,11,19]

现在让我们调用pop_front()

我们得到了

 D[5,10,7,11,19]
 Min[5,7,11,19]

最低为5

让我们再次调用pop_front()

说明:pop_front将从D中删除5,但它也会弹出Min的前元素,因为它等于D的前元素(5)。

 D[10,7,11,19]
 Min[7,11,19]

最小值为7.:)

答案 3 :(得分:3)

使用一个双端队列(A)存储元素,使用另一个双端队列(B)存储最小值。

当x入队时,将其推回到A并保持pop_backing B直到B的后面小于x,然后push_back x到B.

将A,pop_front A作为返回值出列,如果它等于B的前面,则pop_front B也是。

获得A的最小值时,使用B的前面作为返回值。

dequeue和getmin显然是O(1)。对于enqueue操作,请考虑n个元素的push_back。有一个push_back到A,n push_back到B和最多n个pop_back的B,因为每个元素将保留在B中或从B弹出一次。总共有O(3n)操作,因此摊销成本为O (1)以及入队。

最后这个算法工作的原因是当你将x排入A时,如果B中的元素大于x,它们现在永远不会是最小值,因为x将保留在队列中比B中的任何元素长(队列是FIFO)。因此,在将x推入B之前,我们需要在B(从后面)中弹出大于x的元素。

from collections import deque


class MinQueue(deque):
    def __init__(self):
        deque.__init__(self)
        self.minq = deque()

    def push_rear(self, x):
        self.append(x)
        while len(self.minq) > 0 and self.minq[-1] > x:
            self.minq.pop()
        self.minq.append(x)

    def pop_front(self):
        x = self.popleft()
        if self.minq[0] == x:
            self.minq.popleft()
        return(x)

    def get_min(self):
        return(self.minq[0])

答案 4 :(得分:1)

如果你不介意存储一些额外的数据,那么存储最小值应该是微不足道的。如果new或者删除的元素是最小值,则push和pop可以更新值,返回最小值就像获取变量的值一样简单。

这假设get_min()不会改变数据;如果你想要像pop_min()那样(即删除最小元素),你可以简单地存储一个指向实际元素及其前面元素(如果有的话)的指针,并使用push_rear()和pop_front()相应地更新它们。同样。

评论后修改:

显然,在这些操作的最小变化的情况下,这会导致O(n)推送和弹出,因此不能严格满足要求。

答案 5 :(得分:1)

此问题的解决方案,包括代码,可在此处找到: http://discuss.joelonsoftware.com/default.asp?interview.11.742223.32

答案 6 :(得分:1)

您实际上可以使用LinkedList来维护队列。

LinkedList中的每个元素都是Type

class LinkedListElement
{
   LinkedListElement next;
   int currentMin;
}

你可以有两个指针一个指向开始,另一个指向结束。

如果您将一个元素添加到队列的开头。检查Start指针和要插入的节点。如果要插入currentmin的节点小于start currentmin节点,则插入currentmin是最小值。否则用start currentmin更新currentmin。

对于enque重复相同的事情。

答案 7 :(得分:0)

我们知道push和pop是恒定时间操作[确切地说是O(1)]。

但是当我们想到get_min()[即找到队列中的当前最小数量]时,通常首先想到的是每次发出最小元素的请求时搜索整个队列。但这永远不会给出恒定的时间操作,这是问题的主要目的。

这通常在采访中经常被问到,所以你必须知道这个伎俩

要做到这一点,我们必须使用另外两个队列来保持最小元素的跟踪,我们必须继续修改这两个队列,因为我们在队列上进行推送和弹出操作,以便在O中获得最小元素( 1)时间。

这是基于上述方法的自描述sudo代码。

    Queue q, minq1, minq2;
    isMinq1Current=true;   
    void push(int a)
    {
      q.push(a);
      if(isMinq1Current)
      {
        if(minq1.empty) minq1.push(a);
        else
        {
          while(!minq1.empty && minq1.top < =a) minq2.push(minq1.pop());
          minq2.push(a);
          while(!minq1.empty) minq1.pop();
          isMinq1Current=false;
        }
      }
      else
      {
        //mirror if(isMinq1Current) branch. 
      }
    }

    int pop()
    { 
      int a = q.pop();
      if(isMinq1Current)
      {
        if(a==minq1.top) minq1.pop();
      }
      else
      {
        //mirror if(isMinq1Current) branch.    
      }
    return a;
    }

答案 8 :(得分:0)

#include <iostream>
#include <queue>
#include <deque>
using namespace std;

queue<int> main_queue;
deque<int> min_queue;

void clearQueue(deque<int> &q)
{
  while(q.empty() == false) q.pop_front();
}

void PushRear(int elem)
{
  main_queue.push(elem);

  if(min_queue.empty() == false && elem < min_queue.front())
  {
      clearQueue(min_queue);
  }

  while(min_queue.empty() == false && elem < min_queue.back())
  {
      min_queue.pop_back();
  }

  min_queue.push_back(elem);
}

void PopFront() 
{
  int elem = main_queue.front();
  main_queue.pop();

  if (elem == min_queue.front())
  {
       min_queue.pop_front();
  }
}

int GetMin() 
{ 
  return min_queue.front(); 
}

int main()
{
  PushRear(1);
  PushRear(-1);
  PushRear(2);

  cout<<GetMin()<<endl;
  PopFront();
  PopFront();
  cout<<GetMin()<<endl;

  return 0;
}

答案 9 :(得分:0)

此解决方案包含2个队列:
 1. main_q - 存储输入数字  2. min_q - 按照我们将描述的某些规则存储最小数字(出现在MainQ.enqueue(x),MainQ.dequeue(),MainQ.get_min())中。

这是Python中的代码。队列是使用List实现的 主要思想在于MainQ.enqueue(x),MainQ.dequeue(),MainQ.get_min()函数。
一个关键假设是清空队列需要o(0)。
最后提供了测试。

import numbers

class EmptyQueueException(Exception):
    pass

class BaseQ():
    def __init__(self):
        self.l = list()

    def enqueue(self, x):
        assert isinstance(x, numbers.Number)
        self.l.append(x)

    def dequeue(self):
        return self.l.pop(0)

    def peek_first(self):
        return self.l[0]

    def peek_last(self):
        return self.l[len(self.l)-1]

    def empty(self):
        return self.l==None or len(self.l)==0

    def clear(self):
        self.l=[]

class MainQ(BaseQ):
    def __init__(self, min_q):
        super().__init__()
        self.min_q = min_q

    def enqueue(self, x):
        super().enqueue(x)
        if self.min_q.empty():
            self.min_q.enqueue(x)
        elif x > self.min_q.peek_last():
            self.min_q.enqueue(x)
        else: # x <= self.min_q.peek_last():
            self.min_q.clear()
            self.min_q.enqueue(x)

    def dequeue(self):
        if self.empty():
            raise EmptyQueueException("Queue is empty")
        x = super().dequeue()
        if x == self.min_q.peek_first():
            self.min_q.dequeue()
        return x

    def get_min(self):
        if self.empty():
            raise EmptyQueueException("Queue is empty, NO minimum")
        return self.min_q.peek_first()

INPUT_NUMS = (("+", 5), ("+", 10), ("+", 3), ("+", 6), ("+", 1), ("+", 2), ("+", 4), ("+", -4), ("+", 100), ("+", -40),
              ("-",None), ("-",None), ("-",None), ("+",-400), ("+",90), ("-",None),
              ("-",None), ("-",None), ("-",None), ("-",None), ("-",None), ("-",None), ("-",None), ("-",None))

if __name__ == '__main__':
    min_q = BaseQ()
    main_q = MainQ(min_q)

    try:
        for operator, i in INPUT_NUMS:
            if operator=="+":
                main_q.enqueue(i)
                print("Added {} ; Min is: {}".format(i,main_q.get_min()))
                print("main_q = {}".format(main_q.l))
                print("min_q = {}".format(main_q.min_q.l))
                print("==========")
            else:
                x = main_q.dequeue()
                print("Removed {} ; Min is: {}".format(x,main_q.get_min()))
                print("main_q = {}".format(main_q.l))
                print("min_q = {}".format(main_q.min_q.l))
                print("==========")
    except Exception as e:
        print("exception: {}".format(e))

上述测试的输出是:

"C:\Program Files\Python35\python.exe" C:/dev/python/py3_pocs/proj1/priority_queue.py
Added 5 ; Min is: 5
main_q = [5]
min_q = [5]
==========
Added 10 ; Min is: 5
main_q = [5, 10]
min_q = [5, 10]
==========
Added 3 ; Min is: 3
main_q = [5, 10, 3]
min_q = [3]
==========
Added 6 ; Min is: 3
main_q = [5, 10, 3, 6]
min_q = [3, 6]
==========
Added 1 ; Min is: 1
main_q = [5, 10, 3, 6, 1]
min_q = [1]
==========
Added 2 ; Min is: 1
main_q = [5, 10, 3, 6, 1, 2]
min_q = [1, 2]
==========
Added 4 ; Min is: 1
main_q = [5, 10, 3, 6, 1, 2, 4]
min_q = [1, 2, 4]
==========
Added -4 ; Min is: -4
main_q = [5, 10, 3, 6, 1, 2, 4, -4]
min_q = [-4]
==========
Added 100 ; Min is: -4
main_q = [5, 10, 3, 6, 1, 2, 4, -4, 100]
min_q = [-4, 100]
==========
Added -40 ; Min is: -40
main_q = [5, 10, 3, 6, 1, 2, 4, -4, 100, -40]
min_q = [-40]
==========
Removed 5 ; Min is: -40
main_q = [10, 3, 6, 1, 2, 4, -4, 100, -40]
min_q = [-40]
==========
Removed 10 ; Min is: -40
main_q = [3, 6, 1, 2, 4, -4, 100, -40]
min_q = [-40]
==========
Removed 3 ; Min is: -40
main_q = [6, 1, 2, 4, -4, 100, -40]
min_q = [-40]
==========
Added -400 ; Min is: -400
main_q = [6, 1, 2, 4, -4, 100, -40, -400]
min_q = [-400]
==========
Added 90 ; Min is: -400
main_q = [6, 1, 2, 4, -4, 100, -40, -400, 90]
min_q = [-400, 90]
==========
Removed 6 ; Min is: -400
main_q = [1, 2, 4, -4, 100, -40, -400, 90]
min_q = [-400, 90]
==========
Removed 1 ; Min is: -400
main_q = [2, 4, -4, 100, -40, -400, 90]
min_q = [-400, 90]
==========
Removed 2 ; Min is: -400
main_q = [4, -4, 100, -40, -400, 90]
min_q = [-400, 90]
==========
Removed 4 ; Min is: -400
main_q = [-4, 100, -40, -400, 90]
min_q = [-400, 90]
==========
Removed -4 ; Min is: -400
main_q = [100, -40, -400, 90]
min_q = [-400, 90]
==========
Removed 100 ; Min is: -400
main_q = [-40, -400, 90]
min_q = [-400, 90]
==========
Removed -40 ; Min is: -400
main_q = [-400, 90]
min_q = [-400, 90]
==========
Removed -400 ; Min is: 90
main_q = [90]
min_q = [90]
==========
exception: Queue is empty, NO minimum

Process finished with exit code 0

答案 10 :(得分:0)

Java实现     

import java.io.*;
import java.util.*;

public class queueMin {
    static class stack {

        private Node<Integer> head;

        public void push(int data) {
            Node<Integer> newNode = new Node<Integer>(data);
            if(null == head) {
                head = newNode;
            } else {
                Node<Integer> prev = head;
                head = newNode;
                head.setNext(prev);
            }
        }

        public int pop() {
            int data = -1;
            if(null == head){
                System.out.println("Error Nothing to pop");
            } else {
                data = head.getData();
                head = head.getNext();
            }

            return data;
        }

        public int peek(){
            if(null == head){
                System.out.println("Error Nothing to pop");
                return -1;
            } else {
                return head.getData();
            }
        }

        public boolean isEmpty(){
            return null == head;
        }
    }

    static class stackMin extends stack {
        private stack s2;

        public stackMin(){
            s2 = new stack();
        }

        public void push(int data){
            if(data <= getMin()){
                s2.push(data);
            }

            super.push(data);
        }

        public int pop(){
            int value = super.pop();
            if(value == getMin()) {
                s2.pop();
            }
            return value;
        }

        public int getMin(){
            if(s2.isEmpty()) {
                return Integer.MAX_VALUE;
            }
            return s2.peek();
        }
    }

     static class Queue {

        private stackMin s1, s2;

        public Queue(){
            s1 = new stackMin();
            s2 = new stackMin();
        }

        public  void enQueue(int data) {
            s1.push(data);
        }

        public  int deQueue() {
            if(s2.isEmpty()) {
                while(!s1.isEmpty()) {
                    s2.push(s1.pop());
                }
            }

            return s2.pop();
        }

        public int getMin(){
            return Math.min(s1.isEmpty() ? Integer.MAX_VALUE : s1.getMin(), s2.isEmpty() ? Integer.MAX_VALUE : s2.getMin());
        }

    }



   static class Node<T> {
        private T data;
        private T min;
        private Node<T> next;

        public Node(T data){
            this.data = data;
            this.next = null;
        }


        public void setNext(Node<T> next){
            this.next = next;
        }

        public T getData(){
            return this.data;
        }

        public Node<T> getNext(){
            return this.next;
        }

        public void setMin(T min){
            this.min = min;
        }

        public T getMin(){
            return this.min;
        }
    }

    public static void main(String args[]){
       try {
           FastScanner in = newInput();
           PrintWriter out = newOutput();
          // System.out.println(out);
           Queue q = new Queue();
           int t = in.nextInt();
           while(t-- > 0) {
               String[] inp = in.nextLine().split(" ");
               switch (inp[0]) {
                   case "+":
                       q.enQueue(Integer.parseInt(inp[1]));
                       break;
                   case "-":
                       q.deQueue();
                       break;
                   case "?":
                       out.println(q.getMin());
                   default:
                       break;
               }
           }
           out.flush();
           out.close();

       } catch(IOException e){
          e.printStackTrace();
       }
    }

    static class FastScanner {
        static BufferedReader br;
        static StringTokenizer st;

        FastScanner(File f) {
            try {
                br = new BufferedReader(new FileReader(f));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
        public FastScanner(InputStream f) {
            br = new BufferedReader(new InputStreamReader(f));
        }
        String next() {
            while (st == null || !st.hasMoreTokens()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        String nextLine(){
            String str = "";
            try {
                str = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return str;
        }

        int nextInt() {
            return Integer.parseInt(next());
        }
        long nextLong() {
            return Long.parseLong(next());
        }
        double nextDoulbe() {
            return Double.parseDouble(next());
        }
    }

    static FastScanner newInput() throws IOException {
        if (System.getProperty("JUDGE") != null) {
            return new FastScanner(new File("input.txt"));
        } else {
            return new FastScanner(System.in);
        }
    }
    static PrintWriter newOutput() throws IOException {
        if (System.getProperty("JUDGE") != null) {
            return new PrintWriter("output.txt");
        } else {
            return new PrintWriter(System.out);
        }
    }
}

答案 11 :(得分:0)

JavaScript implementation

(Credit to adamax's solution;我 松散地 基于它的实现。跳到底部查看完整注释的代码或阅读以下常规步骤。请注意,这会在O(1)常量时间中找到最大值,而不是最小值 - 易于更改):

  

一般的想法是在构造MaxQueue时创建两个堆栈(我使用链接列表作为底层Stack数据结构 - 不包含在代码中;但是任何{{1}只要用O(1)插入/删除实现它就会做。一个我们大多数Stack来自(pop),而我们主要是dqStack到(push)。

<小时/> 插入:O(1)最坏情况

  

对于eqStack,如果enqueue为空,我们将MaxQueue的值与push以及元组中的当前最大值一起dqStack (相同的值,因为它是MaxQueue中唯一的值); e.g:

const m = new MaxQueue();

m.enqueue(6);

/*
the dqStack now looks like:
[6, 6] - [value, max]
*/
  

如果MaxQueue不为空,我们push只有eqStack;

m.enqueue(7);
m.enqueue(8);

/*
dqStack:         eqStack: 8
         [6, 6]           7 - just the value
*/
  

然后,更新元组中的最大值。

/*
dqStack:         eqStack: 8
         [6, 8]           7
*/

<小时/> 删除:O(1)摊销

  

dequeue我们pop dqStack来自m.dequeue(); > 6 // equivalent to: /* const tuple = m.dqStack.pop() // [6, 8] tuple[0]; > 6 */ 并从元组返回值。

dqStack
  

然后,如果eqStack为空,请将dqStack中的所有值移至// if we build a MaxQueue const maxQ = new MaxQueue(3, 5, 2, 4, 1); /* the stacks will look like: dqStack: eqStack: 1 4 2 [3, 5] 5 */ ,例如:

maxQ.dequeue(); // pops from dqStack (now empty), so move all from eqStack to dqStack
> 3

// as dequeue moves one value over, it checks if it's greater than the ***previous max*** and stores the max at tuple[1], i.e., [data, max]:
/*
dqStack: [5, 5] => 5 > 4 - update                          eqStack:
         [2, 4] => 2 < 4 - no update                         
         [4, 4] => 4 > 1 - update                            
         [1, 1] => 1st value moved over so max is itself            empty
*/
  

随着每个值的移动,我们会检查它是否大于最大到目前为止并将其存储在每个元组中:

dqStack
  

由于每个值最多移动一次dequeue ,我们可以说getMax的摊销时间复杂度为O(1)。

<小时/> 查找最大值:O(1)最差情况

  

然后,在任何时间点,我们都可以调用MaxQueue来检索O(1)常数时间内的当前最大值。只要dqStack不为空,就可以轻松地从maxQ.getMax(); > 5 // equivalent to calling peek on the dqStack and pulling out the maximum value: /* const peekedTuple = maxQ.dqStack.peek(); // [5, 5] peekedTuple[1]; > 5 */ 中的下一个元组中提取最大值。

class MaxQueue {
  constructor(...data) {
    // create a dequeue Stack from which we'll pop
    this.dqStack = new Stack();
    // create an enqueue Stack to which we'll push
    this.eqStack = new Stack();
    // if enqueueing data at construction, iterate through data and enqueue each
    if (data.length) for (const datum of data) this.enqueue(datum);
  }
  enqueue(data) { // O(1) constant insertion time
    // if the MaxQueue is empty,
    if (!this.peek()) {
      // push data to the dequeue Stack and indicate it's the max;
      this.dqStack.push([data, data]); // e.g., enqueue(8) ==> [data: 8, max: 8]
    } else {
      // otherwise, the MaxQueue is not empty; push data to enqueue Stack
      this.eqStack.push(data);
      // save a reference to the tuple that's next in line to be dequeued
      const next = this.dqStack.peek();
      // if the enqueueing data is > the max in that tuple, update it
      if (data > next[1]) next[1] = data;
    }
  }
  moveAllFromEqToDq() { // O(1) amortized as each value will move at most once
    // start max at -Infinity for comparison with the first value
    let max = -Infinity;
    // until enqueue Stack is empty,
    while (this.eqStack.peek()) {
      // pop from enqueue Stack and save its data
      const data = this.eqStack.pop();
      // if data is > max, set max to data
      if (data > max) max = data;
      // push to dequeue Stack and indicate the current max; e.g., [data: 7: max: 8]
      this.dqStack.push([data, max]);
    }
  }
  dequeue() { // O(1) amortized deletion due to calling moveAllFromEqToDq from time-to-time
    // if the MaxQueue is empty, return undefined
    if (!this.peek()) return;
    // pop from the dequeue Stack and save it's data
    const [data] = this.dqStack.pop();
    // if there's no data left in dequeue Stack, move all data from enqueue Stack
    if (!this.dqStack.peek()) this.moveAllFromEqToDq();
    // return the data
    return data;
  }
  peek() { // O(1) constant peek time
    // if the MaxQueue is empty, return undefined
    if (!this.dqStack.peek()) return;
    // peek at dequeue Stack and return its data
    return this.dqStack.peek()[0];
  }
  getMax() { // O(1) constant time to find maximum value
    // if the MaxQueue is empty, return undefined
    if (!this.peek()) return;
    // peek at dequeue Stack and return the current max
    return this.dqStack.peek()[1];
  }
}

<小时/>

代码

&#13;
&#13;
{{1}}
&#13;
&#13;
&#13;