从队列中获取O(1)时间的最小值/最大值?

如何在0(1)时间复杂度的任何时间从队列中检索max和min元素? 之前我使用Collections.max和min来查找元素,但这将是0(n)。

您只有两种方法可以获得最小/最大操作的O(1):

  • 如果结构已排序,您知道最大/最小位置
  • 如果结构未排序且仅允许插入:您可以在每次插入项目时重新计算最小值/最大值并单独存储值
  • 如果结构没有排序并允许插入和删除:我认为你不能做得比O(n)更好, 除非你使用多个集合 (但该解决方案不支持删除任何元素,只有头/尾元素,应该是队列的情况)。

存在这样的结构,其作用类似于队列,但允许您在恒定时间内检索最小/最大值,实际上不是严格恒定的,它是分摊的常量时间(可以猜测命名为最小/最大队列)。 有两种方法可以实现它 – 使用两个堆栈或使用队列和双端队列。

Deque实现看起来更像这样(语言不可知):

所以我们有一个最大元素的双端队列,前面的那个是所需的最大元素,以及一个标准队列。

推动操作

  1. 如果队列为空,只需按下队列和双端队列上的元素即可。
  2. 如果队列不为空,则按下队列中的元素,从deque的后面开始删除严格小于我们正在推送的元素的所有元素(它们将不会是最大值,因为推送的元素更大并将在队列中持续更长时间)并将当前元素推送到双端队列的背面

删除操作

  1. 如果双端队列的前面等于队列的前面,则弹出两个(从前面开始)
  2. 如果双端队列的前端不等于队列的前面然后只弹出队列,则poped元素肯定不是最大的。

获得最大值

  1. 它只是双端队列的第一个元素。

(应该添加许多参数以明确其工作原理,但下面提供的第二个版本可能是这种必要性的答案)

Stack实现非常相似,我认为实现起来可能要长一些,但也许更容易掌握。 首先要注意的是,很容易将最大元素存储在堆栈中 – 简单的练习(对于懒惰的 – 使用find-min / find-max的堆栈比O(n)更有效? )。 第二部分,如果第一次看到,可能有点棘手,是使用两个堆栈实现队列非常容易,可以在这里找到 – 如何使用两个堆栈实现队列? 。 基本上就是这样 – 如果我们可以获得两个堆栈的最大元素,我们就可以获得整个队列的最大元素(如果你想要一个更正式的参数,取最大值是关联的或类似的东西,但我打赌你不要不,这很明显。

最小版本以类似方式完成。

一切也可以在O(nlogn)时间内使用一组(或类似的东西)来完成,但它没有意义,因为O(n)中的常量非常小,它应该更快,但更容易实现。

第一版的非有趣部分:

希望我帮了一下。 并希望没有说错。 如果需要,可以在C ++ / C中提供简单的实现。 将不胜感激任何关于表格的反馈,因为这是我在任何地方的第一篇文章:)(英语不是我的母语)。 对正确性的一些确认也会很棒。

编辑:因为这个答案给了我一些观点,我觉得有必要对它进行一点清理,也要稍微扩展一下。

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

我将存储两个字段minIndexmaxIndex ,它们将分别在数据结构中存储索引位置的最小值和最大值。

将新元素添加到队列时,请检查以下两项内容:

  1. 元素小于minIndex位置的当前最小元素; 如果是这样,在插入后更新minIndex的值。
  2. 元素大于maxIndex位置的当前最大元素,并相应地更新引用。

这将为您提供当前最小值和最大值的O(1)渐近线。

这不是一个真正的队列,但你可以实现Min-Max Heap。

http://en.wikipedia.org/wiki/Min-max_heap

基本上,它是一个堆,它具有偶数级别的最大堆属性,以及奇数级别的最小堆属性。

它具有O(1)MIN()和O(1)MAX()操作。 然而,迭代相当棘手,但它可以工作并满足您的要求。

我在这里发布完整的代码,以便在一个恒定的时间内在队列中找到MIN和MAX。 如果您有任何疑问,请随时与我联系。

队列

// Queue Interface package com.java.util.collection.advance.datastructure.queue; public interface Queue{ boolean addR(E e); E removeL(); E element(); E elementR(); boolean isFull(); boolean isEmpty(); void trim(); } 

双端队列

 package com.java.util.collection.advance.datastructure.queue; /** * A deque is a double-ended queue. You can insert items at either end and delete them * from either end. The methods might be called insertLeft() and insertRight(), and * removeLeft() and removeRight(). * @author vsinha * * @param  */ public interface DeQueue extends Queue{ boolean addL(E element); E removeR(); } 

FindMinMaxQueue

 package com.java.util.collection.advance.datastructure.queue; @SuppressWarnings("hiding") public interface FindMinMaxQueue extends Queue{ public Integer min(); public Integer max(); } 

myQueue中

 package com.java.util.collection.advance.datastructure.queue; import java.util.Arrays; public class MyQueue implements Queue,DeQueue{ protected int front = 0; protected int rear =-1; protected E[] elements =null; private static final int DEFAULT_INTIAL_CAPACITY =100; private int size =0; public MyQueue(){ this(DEFAULT_INTIAL_CAPACITY); } @SuppressWarnings("unchecked") public MyQueue(int intialCapacity){ if(intialCapacity < 0){ throw new IllegalArgumentException("intial capacity can't be null"); } elements =(E[]) new Object[intialCapacity]; } @Override public boolean addR(E e) { if(! isFull()) { elements[++rear] = e; size++; return true; } return false; } @Override public E removeL() { E element =null; if(!isEmpty()){ element=elements[front]; // Nullify the reference elements[front] =null; ++front; --size; } return element; } @Override public E element() { E element =null; if(!isEmpty()){ element=elements[front]; } return element; } @Override public E elementR() { E element =null; if(!isEmpty()){ element=elements[rear]; } return element; } public boolean isFull() { return rear == elements.length; } public boolean isEmpty() { return size == 0; } Override public String toString() { return "MyQueue [front=" + front + ", rear=" + rear + ", elements=" + Arrays.toString(elements) + ", size=" + size + "]"; } @Override public void trim() { @SuppressWarnings("unchecked") E[] dest =(E[]) new Object[size]; System.arraycopy(elements, front, dest, 0, size); elements = dest; front =0; rear=size-1; } @Override public boolean addL(E element) { if(front != 0) { elements[--front] = element; size++; return true; } return false; } @Override public E removeR() { E element =null; if(size > 0) { element=elements[rear]; // Nullify the reference elements[rear] =null; --rear; --size; } return element; } } 

MinAndMaxFinderQueue

 package com.java.util.collection.advance.datastructure.queue; public class MinAndMaxFinderQueue extends MyQueue implements FindMinMaxQueue { private Queue maxValuesQueue =null; private Queue minValuesQueue =null; public MinAndMaxFinderQueue (int intialCapacity){ super(intialCapacity); maxValuesQueue =new MyQueue(intialCapacity); minValuesQueue =new MyQueue(intialCapacity); } @Override public boolean addR(Integer e) { if(super.addR(e)){ if(max() == null || max() <= e){ maxValuesQueue.addR(e); } if(min() == null || min() >= e){ minValuesQueue.addR(e); } return true; } return false; } @Override public Integer removeL() { Integer element =super.removeL(); if(element !=null){ if(maxValuesQueue.element() == element){ maxValuesQueue.removeL(); } if(minValuesQueue.element() == element){ minValuesQueue.removeL(); } } //Need to re-generate MIN and MAX queue when the main queue is not empty and min/max queue is empty regenerateMin(); regenerateMax(); return element; } private void regenerateMin(){ Integer current =null; if(!super.isEmpty() && min() ==null){ for(int front = super.front; front<= super.rear;front++){ current = (Integer)elements[front]; if(min() == null || min() >= current){ minValuesQueue.addR(current); } } } } private void regenerateMax(){ Integer current =null; if(!super.isEmpty() && max() ==null){ for(int front = super.front; front<= super.rear;front++){ current = (Integer)elements[front]; if(max() == null || max() <= current){ maxValuesQueue.addR(current); } } } } public Integer min() { return minValuesQueue.elementR(); } public Integer max() { return maxValuesQueue.elementR(); } @Override public String toString() { return super.toString()+"\nMinAndMaxFinderQueue [maxValuesQueue=" + maxValuesQueue + ", minValuesQueue=" + minValuesQueue + "]"; } } 

测试

 //Test class package com.java.util.collection.advance.datastructure.queue; import java.util.Random; public class MinMaxQueueFinderApp { public static void main(String[] args) { FindMinMaxQueue queue =new MinAndMaxFinderQueue(10); Random random =new Random(); for(int i =0; i< 10; i++){ queue.addR(random.nextInt(100)); System.out.println(queue); System.out.println("MAX :"+queue.max()); System.out.println("MIN :"+queue.min()); } System.out.println(queue); System.out.println("MAX :"+queue.max()); System.out.println("MIN :"+queue.min()); queue.removeL(); System.out.println(queue); System.out.println("MAX :"+queue.max()); System.out.println("MIN :"+queue.min()); queue.removeL(); System.out.println(queue); System.out.println("MAX :"+queue.max()); System.out.println("MIN :"+queue.min()); queue.removeL(); System.out.println(queue); System.out.println("MAX :"+queue.max()); System.out.println("MIN :"+queue.min()); queue.removeL(); System.out.println(queue); System.out.println("MAX :"+queue.max()); System.out.println("MIN :"+queue.min()); queue.removeL(); System.out.println(queue); System.out.println("MAX :"+queue.max()); System.out.println("MIN :"+queue.min()); System.out.println(queue); System.out.println("MAX :"+queue.max()); System.out.println("MIN :"+queue.min()); } } 

我怀疑你正在尝试实现PriorityQueue的function。 这是一个排序队列,其中O(log N)得到最低值。 我不确定为什么你想要最大的值,因为队列只有一端。