I am wondering if there is a way to implement a stack using as many queues as needed that pushes and pops data in O(1). If there is not any O(1) algorithm , what is the best complexity then?
-
What do you mean by O(1)?smac89– smac892014-10-30 01:25:54 +00:00Commented Oct 30, 2014 at 1:25
-
I mean the time taken by the algorithm should not be dependent to n-the size of the stack. It has to be constantFeri– Feri2014-10-30 01:27:38 +00:00Commented Oct 30, 2014 at 1:27
-
The time taken for algorithm to do what?smac89– smac892014-10-30 01:28:19 +00:00Commented Oct 30, 2014 at 1:28
-
I don't think so. Why would you want to? Intuitively, I'm inclined to say O(n) would be best case.RJinman– RJinman2014-10-30 01:39:57 +00:00Commented Oct 30, 2014 at 1:39
-
1Well if you can implement a O(1) stack using an array, you could just as well use an array of 1-element queues, but that would be pointless. Could you define the problem better? Are you permitted to use arrays or variables, or must the solution consist entirely of queues?RJinman– RJinman2014-10-30 01:53:31 +00:00Commented Oct 30, 2014 at 1:53
3 Answers
If recursively defined queues in queues are allowed then O(1) pushes/pops is possible using the following:
Code:
STACK:
QUEUE q
PUSH (S, x):
QUEUE temp
ENQUEUE(temp, x)
ENQUEUE(temp, S.q)
S.q = temp
POP (S):
ANY x := DEQUEUE(S.q) # Error here if queue is empty
QUEUE S.q := DEQUEUE(S.q)
return x
The result is a recursively formed stack.
If [1,2] represents a stack where dequeue([1,2]) would return 1. Then the data structure if 1 then 3 then 6 were pushed onto the stack would look like this:
[6,[3,[1,[]]]]
5 Comments
You can make a stack with linear-time PUSH and constant-time POP.
Given a queue with functions ENQUEUE and DEQUEUE:
STACK:
QUEUE q
PUSH (S, x):
r := new QUEUE
ENQUEUE(r, x)
while S.q not empty:
v := DEQUEUE(S.q)
ENQUEUE(r, v)
S.q := r
POP (S):
RETURN DEQUEUE(S.q)
EDIT: Alternative solution that doesn't require temporary queue r:
STACK:
QUEUE q
PUSH (S, x):
ENQUEUE(S.q, x)
n := SIZE(S.q) - 1
repeat n times:
v := DEQUEUE(S.q)
ENQUEUE(S.q, v)
POP (S):
RETURN DEQUEUE(S.q)
1 Comment
Here is a C++ implementation of a stack with O(1) push and pop functions.
The interface is similar to std::stack:
void push(const T& val);
void pop();
const T& top() const;
bool empty() const;
Here is the full code. I couldn't think of a way of avoiding the messy type-casts.
#include <iostream>
#include <stack>
#include <queue>
#include <stdexcept>
#define ASSERT(x) \
if (!(x)) { \
std::cout << "Assertion failed at line " << __LINE__ << "\n"; \
} \
template <typename T>
class Stack {
public:
Stack()
: m_head(NULL), m_tail(NULL) {}
void push(const T& val) {
std::queue<void*>* tail = new std::queue<void*>();
tail->push(reinterpret_cast<void*>(m_head));
tail->push(reinterpret_cast<void*>(m_tail));
m_head = new std::queue<T>();
m_head->push(val);
m_tail = tail;
}
void pop() {
if (m_head) {
delete m_head;
m_head = reinterpret_cast<std::queue<T>*>(m_tail->front());
m_tail->pop();
std::queue<void*>* tail = reinterpret_cast<std::queue<void*>*>(m_tail->front());
delete m_tail;
m_tail = tail;
}
}
const T& top() const {
if (!m_head) {
throw std::runtime_error("Error retrieving top element; stack empty");
}
return m_head->front();
}
bool empty() {
return !m_head;
}
private:
std::queue<T>* m_head;
std::queue<void*>* m_tail;
};
int main() {
Stack<int> s;
s.pop();
s.push(0);
ASSERT(s.top() == 0);
s.push(1);
ASSERT(s.top() == 1);
s.push(2);
ASSERT(s.top() == 2);
s.push(3);
ASSERT(s.top() == 3);
s.pop();
ASSERT(s.top() == 2)
s.push(4);
ASSERT(s.top() == 4);
s.push(5);
ASSERT(s.top() == 5);
s.push(6);
ASSERT(s.top() == 6);
s.pop();
ASSERT(s.top() == 5)
s.pop();
ASSERT(s.top() == 4)
s.push(7);
ASSERT(s.top() == 7);
s.pop();
ASSERT(s.top() == 4)
s.pop();
ASSERT(s.top() == 2)
s.pop();
ASSERT(s.top() == 1)
s.pop();
ASSERT(s.top() == 0)
s.pop();
ASSERT(s.empty())
s.pop();
int error = false;
try {
int x = s.top();
}
catch (std::exception&) {
error = true;
}
ASSERT(error == true);
return 0;
}