-
Notifications
You must be signed in to change notification settings - Fork 0
/
Queue.java
executable file
·257 lines (209 loc) · 6.74 KB
/
Queue.java
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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
// package osl.util;
// import java.io.*;
/**
This class provides a fairly efficient implementation of a FIFO
queue. We use an array to implement the queue which is
automatically increased in size when necessary. Note that the queue
is never shrunk in the current implementation.
@author Mark Astley
@version $Revision: 1.5 $ ($Date: 1998/09/07 23:00:37 $)
*/
// public class Queue implements Cloneable, Serializable {
public class Queue {
/**
This constant sets the initial size of a queue when the default
constructor is invoked to create a queue. Users requiring a
different initial size may invoke the appropriate constructor
below.
*/
public static final int INITIAL_SIZE = 10;
/**
This array holds the queue. We use a dynamically growing circular
array to represent the queue. Queue size is doubled when
necessary which should make for a rather efficient implementation.
*/
Object[] theQ;
/**
These two fields hold indices to the first and last element of the
queue respectively. Technically, <em>back</em> points to the
first open spot in the queue rather than the last element.
*/
int front;
int back;
/**
Default constructor for the <em>Queue</em> class.
*/
public Queue() {
theQ = new Object[INITIAL_SIZE];
front=back=0;
}
/**
Alternative constructor for the <em>Queue</em> class which allows
the specification of the initial size of the queue.
@param <b>initialSize</b> The initial size of the new <em>Queue</em>.
*/
public Queue(int initialSize) {
theQ = new Object[initialSize];
front=back=0;
}
/**
This private method is used to double the size of the queue when
more space is required (as a result of calling enqueue). Note
that because the implementation is in terms of a circular array,
we have to be careful when copying elements from the old array to
the new array.
*/
synchronized private void grow() {
Object[] newQ = new Object[2 * theQ.length];
if (back >= front)
System.arraycopy(theQ, front, newQ, front, back - front + 1);
else {
System.arraycopy(theQ, front, newQ, front, theQ.length - front);
System.arraycopy(theQ, 0, newQ, theQ.length, back);
back = front + theQ.length - 1;
}
theQ = newQ;
}
/**
Determine if the queue is empty.
@return <b>true</b> if the queue contains no elements,
<b>false</b> otherwise.
*/
synchronized public boolean empty() {
return (front == back);
}
/**
Add an object to the end of the queue.
@param <b>q</b> A reference to the object to add.
@return <b>void</b>
*/
synchronized public void enqueue(Object q) {
if (((back + 1) % theQ.length) == front)
grow();
theQ[back] = q;
back = (back + 1) % theQ.length;
}
/**
Remove an object from the front of the queue. The returned object
is removed from the queue.
@return A reference to the <b>Object</b> at the front of the
queue. Returns <em>null</em> if the queue is empty.
*/
synchronized public Object dequeue() {
Object toReturn = null;
if (!empty()) {
toReturn = theQ[front];
front = (front + 1) % theQ.length;
}
return toReturn;
}
/**
Get the object at the front of the queue without removing it.
@return A reference to the <b>Object</b> at the front of the
queue.
*/
synchronized public Object peekFront() {
if (!empty())
return theQ[front];
else
return null;
}
/**
Determine how many objects are currently stored in the queue.
@return An <b>int</b> indicating the number of objects in the
queue.
*/
synchronized public int numElements() {
if (front <= back)
return (back - front);
else
return (back + (theQ.length - front));
}
/**
This function allows arbitrary queue elements to be removed.
Elements which are equal (according to the <em>equal</em>
function) to the argument are removed from the queue. Note that
this version of the function only removes the FIRST element
found. Use the <em>removeAll</em> function to remove ALL elements
equal to the argument.
@param <b>rem</b> The object to be removed from the queue.
@return <b>true</b> if an element was removed, <b>false</b>
otherwise.
*/
synchronized public boolean remove(Object rem) {
int i, x, y;
// PRAGMA [debug,osl.util.Queue] Log.println("<Queue.remove> Searching for element: " + rem);
// First track down the element to remove (if there is one)
for(i=front; i != back; i = (i + 1) % theQ.length)
if (rem.equals(theQ[i]))
break;
// If nothing found then return false...
if (i == back)
// PRAGMA [debug,osl.util.Queue] {
// PRAGMA [debug,osl.util.Queue] Log.println("<Queue.remove> Element not found, returning");
return false;
// PRAGMA [debug,osl.util.Queue] } else {
// PRAGMA [debug,osl.util.Queue] Log.println("<Queue.remove> Element found at position: " + i);
// PRAGMA [debug,osl.util.Queue] }
// Otherwise remove the one element. This is a bit of a hack but
// should be fairly efficient.
Object[] newQ = new Object[theQ.length];
for(x=front, y=0; x != back; x = (x + 1) % theQ.length)
if (x != i) {
newQ[y] = theQ[x];
y++;
}
theQ = newQ;
front = 0;
back = y;
return true;
}
/**
This function has the same behavior as <em>remove</em> except that
ALL matching elements are removed from the queue.
@param <b>rem</b> The object to be removed from the queue.
@return The number of elements removed.
*/
synchronized public int removeAll(Object rem) {
int i, match, x, y, z;
// Track down all the elements to remove.
int[] toRemove = new int[numElements()];
for(i=front, match=0; i != back; i = (i + 1) % theQ.length)
if (rem.equals(theQ[i])) {
toRemove[match] = i;
match++;
}
// See if anything matched, if not then just return
if (match == 0)
return 0;
// Now make a new array with all the matching elements removed
Object[] newQ = new Object[theQ.length];
for(x=front, y=0, z=0; x != back; x = (x + 1) % theQ.length)
if (z < match)
if (x != toRemove[z]) {
newQ[y] = theQ[x];
y++;
} else
z++;
else {
newQ[y] = theQ[x];
y++;
}
theQ = newQ;
front = 0;
back = y;
// match holds the number of things we removed
return match;
}
/**
The canonical toString method.
*/
synchronized public String toString() {
String returnVal = "Queue: ";
if (empty())
return returnVal + "no elements";
for(int i=front; i != back; i = (i + 1) % theQ.length)
returnVal = returnVal + theQ[i].toString() + " ";
return returnVal;
}
}