问题
I'm implementing a queue using a circular array, and I'm kind of stuck in the resize()
method implementation (when the array is full).
Inside the enqueue()
method I check if the size of the array equals it's length, and get if it's full. Now, instead of throwing an exception, I'm trying to resize the array.
The thing is, I have two cases to consider
- front <= rear
- rear < front
Which is the best way to copy the elements of the old array into the new, larger one?
I thought it using a for-loop, like:
newArray = new Array[oldArray.length*2];
if (front <= rear) {
for (int i = front; i < rear; i++) {
newArray[i] = oldArray[i];
}
} else {
for (int i = front; i < newArray.length; i++) {
newArray[i] = oldArray[i];
}
for (int j = rear; j < front; j++) {
// i'm using the variable i, the order is maintained
newArray[i] = oldArray[j];
i++;
}
}
Then oldArray
= newArray
, return newArray
and the resize it's done
I'm not sure of the amount of for's used to do this and I'm afraid I lose values.
Can someone tell me if there is a better way to do this?
回答1:
For copying arrays with more than a handful of elements, use System.arraycopy(), since it is usually implemented as native code, e.g. Sun's VM uses hand-coded assembler.
front > rear
Since the data is contiguous, it can remain in the same place in the new array.
System.arraycopy(oldArray, front, newArray, front, front-rear);
front <= rear
The data is non-contiguous, so copy both blocks to the start of the new array.
// copy [rear to end]
System.arraycopy(oldArray, rear, newArray, 0, oldArray.length-rear);
// copy [0 to front]
System.arraycopy(oldArray, 0, newArray, oldArray.length-rear, front);
front = oldArray.length-(rear-front);
rear = 0;
回答2:
Thx a lot for your answers and different solutions! :)
Although using the System.arraycopy() method is the most easy and efficient solution, I had to avoid using it and implement a solution by myself.
So, if someone want to resize() a circular array in a queue implementation without System.arraycopy(), here is my final solution:
private void resize() {
E[] aux = (E[]) new Object[Q.length * 2]; // new array
int i = 0; // use this to control new array positions
int j = f; // use this to control old array positions
boolean rearReached = false;
while (!rearReached) {
rearReached = j % Q.length == r; // is true if we've reached the rear
aux[i] = Q[j % Q.length];
i++;
j++;
}
f = 0;
r = Q.length - 1;
Q = aux;
}
As you can see, I took advantage of the "circular" thing and mapped the positions of the old array to the new array using the % operator.
The resultant array will have the double of capacity and all the elements (keeping the original order, obviously) at the beginning of the new array.
I've tested it and it worked properly. Lemme know if there is any inconvenience with that code.
Regards
回答3:
Think of the blocks of array elements you want to move and where they should go in the new array. Then and use System.arraycopy to do it. You should call arraycopy once if front < rear and twice if rear < front.
回答4:
If your array is full, you either have front == rear - 1
, or rear == 0
and front == length -1
(or the other way around, I don't know your nomenclature). In the second case you can copy your whole array in one step, in the (more general) first case you have two blocks (0 .. front and rear .. length-1) which are to copy.
来源:https://stackoverflow.com/questions/5695042/queue-implementation-with-circular-arrays-which-is-the-best-way-to-resize-a-cir