How can I retrieve the max and min element from a queue at any time in 0(1) time complexity? Earlier I was using Collections.max and min to find the elements but that would be 0(n).
-
9Unless the queue is sorted, you can't... – Baz Aug 21 '12 at 12:03
-
Use Treeset instead of queue. – Santosh Aug 21 '12 at 12:04
-
Can we use other data structures ? – h4ck3d Aug 21 '12 at 12:04
-
8You can create special field that will store max/min whatever you update your queue and read it when needed. – Pshemo Aug 21 '12 at 12:04
-
I am implementing a queue actually , not using the built in ones , so maybe some modification? – h4ck3d Aug 21 '12 at 12:04
-
What queue implementation are you using? – algolicious Aug 21 '12 at 12:05
-
2@Pshemo yes, but updating would require non-constant-time. – Matt Ball Aug 21 '12 at 12:07
-
@MattBall Yes, but I assume that question is about retrieving min/max in O(1). There will always be place in min/max algorithm that will require non-constant-time :) – Pshemo Aug 21 '12 at 12:14
-
Removed. Good thinking by Matt Ball, he had us all going :) – Marko Topolnik Aug 21 '12 at 15:19
-
2Search for min stack O(1). Then search for implement queue using 2 stacks. Combine them and you will have min Queue O(1), O(1) average when pop. – Viet Anh Feb 01 '15 at 05:47
7 Answers
There exist such a structure that acts like a queue but lets you retrieve min/max value in constant time, actually not strictly constant, it is amortized constant time (named min/max queue as you could guess). There are two ways of implementing it - using two stacks or using a queue and a deque.
Deque implementation looks more less like this (language agnostic):
so we have a deque of max elements, the one on the front is the desired max, and a standard queue.
Push operation
- If the queue is empty, just push the element on both, the queue and the deque.
- If the queue is not empty, push the element on the queue, going from the back of the deque delete all elements that are strictly less than the one we are now pushing (they will surly not be the max, since the pushed element is larger and will last on the queue for longer) and push the current element on the back of the deque
Remove operation
- If the front of the deque is equal to the front of the queue then pop both (deque from the front)
- If the front of the deque is not equal to the front of the queue then pop just the queue, the poped element surely is not the largest one.
Get max
- It is just the first element of the deque.
(lots of arguments should be added to make it clear why it works, but the second version presented below may be the answer to this necessity)
The Stack implementation is quite similar, I think it may be a bit longer to implement but perhaps easier to grasp. The first thing to note is that it is easy to store the maximal element at the stack - easy exercise (for the lazy ones - Stack with find-min/find-max more efficient than O(n)?). The second part, perhaps a bit tricky if seen the first time, is that it is quite easy to implement a queue using two stacks, it can be found here - How to implement a queue using two stacks? . And that is basically it - if we can get the maximal element of both of the stacks we can get the maximal element of the whole queue (taking maximum is associative or something like that if you want a more formal argument, but I bet you don't, it is really obvious).
The min versions is done analogically.
Everything may also be done using a set (or something of it's kind) in O(nlogn) time but it is pointless as the constant in O(n) is really small and it should be much faster, yet easy to implement.
NON-INTERESTING parts from the first version:
Hope I helped a little bit. And hope that didn't say anything wrong. Can give a simple implementation in C++/C if required. Would be grateful for any feedback on the form as it is my first post of this type anywhere :) (and English is not my native language). Also some confirmation on the correctness would be great.
EDIT: as this answer got me some points I felt obliged to clean it up a bit, also extending it a bit.
You only have 2 ways to get O(1) for a min/max operation:
- if the structure is sorted and you know where the max / min is located
- if the structure is not sorted and only allows insertion: you can recalculate the min / max every time you insert an item and store the value separately
- if the structure is not sorted and allows insertions and removals: I don't think you can do better than O(n), unless you use more than one collection (but that solution does not support removal of any elements, only head / tail elements, which should be the case with a queue).
-
1I deleted my answer since I'm pretty sure it only works for stacks, and not queues. – Matt Ball Aug 21 '12 at 14:58
-
-
3Search for min stack O(1). Then search for implement queue using 2 stacks. Combine them and you will have min Queue O(1), O(1) average when pop. – Viet Anh Feb 01 '15 at 05:48
I suspect you are trying to implement what a PriorityQueue does. This is a sorted queue which O(log N) to get the lowest value. I not sure why you would want to largest value as a queue only has one end.

- 525,659
- 79
- 751
- 1,130
-
-
Interesting, so you have using off heap memory? (arrays and objects are on the heap) – Peter Lawrey Aug 21 '12 at 20:00
-
What i meant to say was that to implement a PQ , i would need to use min-heap / max-heap , heapify operations ! That is , heap( as a data structure). – h4ck3d Aug 21 '12 at 20:04
-
The builtin PriorityQueue doesn't have those operations http://docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html – Peter Lawrey Aug 21 '12 at 20:06
This isn't really a queue, but you can implement Min-Max Heap.
http://en.wikipedia.org/wiki/Min-max_heap
Basically, it's a heap which has it's max heap property at even levels, and min heap property at odd levels.
It has both O(1) MIN() and O(1) MAX() operations. However it's rather tricky to iterate, but it works and meets your requirements.

- 15,379
- 3
- 47
- 71
-
If the question was to implement a Priority-Queue, min/max heap should be the best case to get min/max in O(1), but still insert and delete (very loosely we can relate then with enqueue and dequeue) will take O(log(n)). – user3234777 Sep 23 '22 at 04:45
I am posting the complete code here to find MIN and MAX in queue in a constant time. Please feel free to contact me if you have any doubt.
Queue
// Queue Interface
package com.java.util.collection.advance.datastructure.queue;
public interface Queue<E>{
boolean addR(E e);
E removeL();
E element();
E elementR();
boolean isFull();
boolean isEmpty();
void trim();
}
Deque
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 <E>
*/
public interface DeQueue<E> extends Queue<E>{
boolean addL(E element);
E removeR();
}
FindMinMaxQueue
package com.java.util.collection.advance.datastructure.queue;
@SuppressWarnings("hiding")
public interface FindMinMaxQueue<Integer> extends Queue<Integer>{
public Integer min();
public Integer max();
}
MyQueue
package com.java.util.collection.advance.datastructure.queue;
import java.util.Arrays;
public class MyQueue<E> implements Queue<E>,DeQueue<E>{
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<Integer> implements FindMinMaxQueue<Integer> {
private Queue<Integer> maxValuesQueue =null;
private Queue<Integer> minValuesQueue =null;
public MinAndMaxFinderQueue (int intialCapacity){
super(intialCapacity);
maxValuesQueue =new MyQueue<Integer>(intialCapacity);
minValuesQueue =new MyQueue<Integer>(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
//Test class
package com.java.util.collection.advance.datastructure.queue;
import java.util.Random;
public class MinMaxQueueFinderApp {
public static void main(String[] args) {
FindMinMaxQueue<Integer> 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());
}
}

- 6,523
- 1
- 25
- 30

- 250
- 3
- 17
I would store two fields minIndex and maxIndex that will store index positions in your data structure for the minimum and maximum value respectively.
When new elements are added to the queue, check for two things:
- The element is less than the current minimum element at the minIndex position; if so update the value of minIndex after insertion.
- The element is greater than the current maximum element at the maxIndex position and update the reference accordingly.
This will give you a O(1) asymptote for the current min and max value.

- 1,182
- 2
- 10
- 14
-
4
-
Ah, yeah; so it is best to create two stack in addition, one for minimum values and the other for maximum values. – algolicious Aug 28 '12 at 08:36
-
2Actually, that won't help you, either. When you add at one end and remove at the other, the queue as a whole transitions between disparate states that are not equal to any previous state. Therefore the history approach is useless. – Marko Topolnik Aug 28 '12 at 08:47
-