Implement stack using a queue

The puzzle is to implement basic stack operations with using only basic queue operations. That is, a queue object is given, we need construct a wrapper for the stack functions, push, pop, which will only use the queue object as its storage, and naturally will have to use the queue operations.

This can be done using only one queue object. Although either the push or the pop complexity will no more be O(1).

The Idea

The idea is pretty simple. We start with an empty queue. For the push operation we simply insert the value to be pushed into the queue. The pop operation needs some manipulation. When we need to pop from the stack (simulated with a queue), first we get the number of elements in the queue, say n, and remove (n-1) elements from the queue and keep on inserting in the queue one by one. That is, we remove the front element from the queue, and immediately insert into the queue in the rear, then we remove the front element from the queue and then immediately insert into the rear, thus we continue upto (n-1)elements. Then we will perform a remove operation, which will actually remove the nthelement of the original state of the queue, and return. Note that the nth element in the queue is the one which was inserted last, and we are returning it first, therefore it works like a pop operation (Last in First Out). The idea is shown below.

Push pseudocode
1
2
3
4
void push (queue_t q)
{
   queue.insert (element);
}
Pop pseudocode
1
2
3
4
5
6
7
8
9
10
11
12
element_type pop (void)
{
   n = queue.element_count ();
  
   for (i from 0 to n - 2) // Only (n-1) elements 0 to (n-2)
   {
     queue_element = queue.remove ();
     queue.insert (queue_element);
   }
   element = queue.remove ();
   return element;
}

Note that in the pop process, because we are inserting the first (n-1) elements in the queue in the same order we are removing, after the for loop termination in pop the state of the queue would have the last element in the queue at the font, and the remaining elements will maintain the same order which they had before the execution of the forloop. At this point we are simply removing the queue’s first element, which happens to beactually the last element in the original state of the queue, is removed and sent. After this the queue has the same elements in the same order except the last element. Which is exactly the behaviour we wanted.

Here is a simple diagram. Assume that the queue representation in the diagram has infinite length, and implemented as a linear queue (not circular) for simplicity.

/** PUSH operation **/
front,rear
   |
   v
+----+----+----+----+----+----+
| 1  |    |    |    |    |    |  push (1) : insert (1)
+----+----+----+----+----+----+
 
 
front  rear
   |     |
   v     V
+----+----+----+----+----+----+
| 1  | 2  |    |    |    |    |  push (2) : insert (2)
+----+----+----+----+----+----+
 
 
 
front            rear
   |               |
   v               V
+----+----+----+----+----+----+
| 1  | 2  | 3  | 4  |    |    |  push (3), push (4) : insert (3), insert (4)
+----+----+----+----+----+----+
/** POP operation **/
 
initial:
 
front            rear
   |               |
   v               V
+----+----+----+----+----+----+
| 1  | 2  | 3  | 4  |    |    |
+----+----+----+----+----+----+
 
popping
 
4 elements present. We will remove first 3 elements and immediately
insert them as follows.
 
      front           rear
        |              |
        v              V
+----+----+----+----+----+----+----+----+
|    | 2  | 3  | 4  | 1  |    |    |    |  queue.insert (queue.remove ());
+----+----+----+----+----+----+----+----+  //first element
 
 
 
           front           rear
             |              |
             v              V
+----+----+----+----+----+----+----+----+
|    |    | 3  | 4  | 1  | 2  |    |    |  queue.insert (queue.remove ());
+----+----+----+----+----+----+----+----+  //second element
 
 
                front           rear
                  |              |
                  v              V
+----+----+----+----+----+----+----+----+
|    |    |    | 4  | 1  | 2  | 3  |    |  queue.insert (queue.remove ());
+----+----+----+----+----+----+----+----+  //third element
 
 
 
                     front      rear
                       |         |
                       v         V
+----+----+----+----+----+----+----+----+
|    |    |    |    | 1  | 2  | 3  |    |  return (queue.remove ());
+----+----+----+----+----+----+----+----+  //return required element 4
 
 
At this point we have popped the last inserted element, and the
queue holds the elements in correct order except the element 4 removed.

Now we go into the implementation, which is pretty simple.

Sourcecode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#include <stdio.h>
#include <stdlib.h>
 
/* Queue structure */
 
#define QUEUE_EMPTY_MAGIC 0xdeadbeef
typedef struct _queue_t
{
   int *arr;
   int rear, front, count, max;
} queue_t;
 
/* Queue operation function prototypes */
queue_t *queue_allocate ( int n);
void queue_insert (queue_t * q, int v);
int queue_remove (queue_t * q);
int queue_count (queue_t * q);
int queue_is_empty (queue_t * q);
 
/* NOTE: Here is the stuff we are interested in */
/* Simulated stack operations START */
 
/* NOTE: passing the queue object, on which we will only operate the
  * queue operations.
  */
void
stack_push (queue_t * q, int v)
{
   queue_insert (q, v);
}
 
int
stack_pop (queue_t * q)
{
   int i, n = queue_count (q);
   int removed_element;
 
   for (i = 0; i < (n - 1); i++)
     {
       removed_element = queue_remove (q);
       queue_insert (q, removed_element);
       /* same as below */
       //queue_insert (q, queue_remove (q))
     }
   removed_element = queue_remove (q);
 
   return removed_element;
}
 
int
stack_is_empty (queue_t * q)
{
   return queue_is_empty (q);
}
 
int
stack_count (queue_t * q)
{
   return queue_count (q);
}
 
/* Simulated stack operations END */
 
 
/* Queue operations START */
 
int
queue_count (queue_t * q)
{
   return q->count;
}
 
queue_t *
queue_allocate ( int n)
{
   queue_t *queue;
 
   queue = malloc ( sizeof (queue_t));
   if (queue == NULL)
     return NULL;
   queue->max = n;
 
   queue->arr = malloc ( sizeof ( int ) * n);
   queue->rear = n - 1;
   queue->front = n - 1;
 
   return queue;
}
 
void
queue_insert (queue_t * q, int v)
{
   if (q->count == q->max)
     return ;
 
   q->rear = (q->rear + 1) % q->max;
   q->arr[q->rear] = v;
   q->count++;
}
 
int
queue_remove (queue_t * q)
{
   int retval;
 
   /* magic number if queue is empty */
   if (q->count == 0)
     return QUEUE_EMPTY_MAGIC;
 
   q->front = (q->front + 1) % q->max;
   retval = q->arr[q->front];
   q->count--;
 
   return retval;
}
 
int
queue_is_empty (queue_t * q)
{
   return (q->count == 0);
}
 
/* Queue operations END */
 
 
 
/* For demo */
void
queue_display (queue_t * q)
{
   int i = (q->front + 1) % q->max, elements = queue_count (q);
 
 
   while (elements--)
     {
       printf ( "[%d], " , q->arr[i]);
       i = (i >= q->max) ? 0 : (i + 1);
     }
}
 
#define MAX 128
int
main ( void )
{
   queue_t *q;
   int x, select;
   /* Static allocation */
   q = queue_allocate (MAX);
 
 
   do
     {
       printf ( "\n[1] Push\n[2] Pop\n[0] Exit" );
       printf ( "\nChoice: " );
       scanf ( " %d" , &select);
 
       switch (select)
         {
         case 1:
           printf ( "\nEnter value to Push:" );
           scanf ( " %d" , &x);
           /* Pushing */
           stack_push (q, x);
 
           printf ( "\n\n__________________________\nCurrent Queue:\n" );
 
           queue_display (q);
           printf ( "\n\nPushed Value: %d" , x);
 
           printf ( "\n__________________________\n" );
           break ;
 
         case 2:
           /* Popping */
           x = stack_pop (q);
 
           printf ( "\n\n\n\n__________________________\nCurrent Queue:\n" );
 
           queue_display (q);
           if (x == QUEUE_EMPTY_MAGIC)
             printf ( "\n\nNo values removed" );
           else
             printf ( "\n\nPopped Value: %d" , x);
 
           printf ( "\n__________________________\n" );
           break ;
 
         case 0:
           printf ( "\nQutting.\n" );
           return 0;
 
         default :
           printf ( "\nQutting.\n" );
           return 0;
         }
     }
   while (1);
 
   return 0;
}

This code is basically divided in three parts. One is a hand made implementation of a circular queue of integers. Next the stack operations using the queue, and a demo driver which will demonstrate the code interactively. In the code, the stack simulating functions are highlighted. The stack empty and stack element count functions are implemented here with the queue functions. Although it looks a bit messy but i couldn’t stop myself writing the C code and post, although a CPP implementation would have been cleaner. Note that the implementation considers that the queue (stack) size is static defined by the MAXmacro, and also the queue will only contain integers. The code is straight forward therefore i am not going to describe it. Although if there is any problem feel free to drop a comment.

Here is a stack wrapper class in CPP using the STL queue class. Thanks to Subhendu Berafor writing it for me.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <queue>
 
using namespace std;
 
template < class T> class mystack
{
   private :
     queue <T> Q;
 
   public :
     void ms_push (T data);
     T ms_pop ();
};
 
template < class T> void mystack <T>::ms_push (T data)
{
   Q.push (data);
}
 
template < class T> T mystack <T>::ms_pop ()
{
   T n, temp;
   n = Q.size ();
 
   for ( int i = 0; i < (n - 1); i++)
     {
       temp = Q.front ();
       Q.pop ();
       Q.push (temp);
       /* Same as below */
       //Q.push (Q.pop ());
     }
   temp = Q.front ();
   Q.pop ();
 
   return temp;
}

The Other way

The other way is just the opposite. When pushing the element, instead of directly inserting it in the queue we can insert a new element in the queue and then if there are n elements in the queue, then we remove and insert (n-1). In this case while popping we simply return the first element. Here is what i am trying to say:

Pop pseudocode
1
2
3
4
int stack_pop (queue_data *q)
{
   return queue_remove (q);
}
Push pseudocode
1
2
3
4
5
6
7
8
9
10
void stack_push (queue_data *q, int val)
{
   int old_count = queue_get_element_count (q), i;
 
   queue_insert (q, val);
   for (i=0; i<old_count; i++)
   {
     queue_insert (q, queue_remove (q));
   }
}

Same stuff is in here in my answer:http://stackoverflow.com/questions/688276/implement-stack-using-two-queues

Not posting the code for this one.

Complexity

Clearly, if we do the dequeue, enqueue operation in the pop function, then it will have a execution growth upperbound of O(n) where n is the length of the queue, and the pushoperation will have O(1) time bound. The reverse is valid for the “Other Method”.

What’s the use? I don’t know, it’s just a puzzle that i came by.

What about the reverse, that is implementing a queue with a stack? I will post it soon as i get some time (The ASCII art and making sure things work is *pain*).

Check out the new post which does the opposite: Implement queue using stack

1、资源项目源码均已通过严格测试验证,保证能够正常运行;、 2项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行;、 2项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值