简体   繁体   中英

Queue implementation with circular arrays: Which is the best way to resize a circular array?

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

  1. front <= rear
  2. 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?

For copying arrays with more than a handful of elements, use System.arraycopy() , since it is usually implemented as native code, eg 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;

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

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM