DualArrayDeque: Building a Deque from Two Stacks
Learn how to implement a DualArrayDequedata structure.
We'll cover the following...
Next, we present a data structure, DualArrayDeque
, that achieves the same performance bounds as an ArrayDeque
by using two ArrayStacks. Although the asymptotic performance of the DualArrayDeque
is no better than that of the ArrayDeque
, it is still worth studying, since it offers a good example of how to make a sophisticated data structure by combining two simpler data structures.
Two ends of a DualArrayDeque
A DualArrayDeque
represents a list using two ArrayStacks. Recall that an ArrayStack
is fast when the operations on it modify elements near the end. A DualArrayDeque
places two ArrayStacks
, called front
and back
, back-to-back so that operations are fast at either end.
List<T> front;List<T> back;
A DualArrayDeque
does not explicitly store the number, , of elements it contains. It doesn’t need to, since it contains n = front.size() + back.size()
elements. Nevertheless, when analyzing the DualArrayDeque
we will still use to denote the number of elements it contains.
int size() {return front.size() + back.size();}
DualArrayDeque
operations
The front
ArrayStack
stores the list elements whose indexes are but stores them in reverse order. The back
ArrayStack
contains list elements with indexes in in the normal order. In this way, get(i)
and set(i, x)
translate into appropriate calls to get(i)
or set(i, x)
on either front
or back
, which take time per operation.
T get(int i) {if (i < front.size()) {return front.get(front.size() - i - 1);} else {return back.get(i - front.size());}}T set(int i, T x) {if (i < front.size()) {return front.set(front.size() - i - 1, x);} else {return back.set(i - front.size(), x);}}
Note that if an index i < front.size()
, then it corresponds to the element of front
at position front.size() − i − 1
, since the elements of front
are stored in reverse order.
Visual demonstration
Adding and removing elements from a DualArrayDeque
is illustrated below. Arrows denote elements being copied. Operations that result in a rebalancing by balance()
are marked with an asterisk.
The add(i, x)
operation manipulates either front
or back
, as appropriate:
void add(int i, T x) {if (i < front.size()) {front.add(front.size() - i, x);} else {back.add(i - front.size(), x);}balance();}
The add(i, x)
method performs rebalancing of the two ArrayStacks
front
and back
, by calling the balance()
method. The implementation of balance()
is described below, but for now it is sufficient to know that balance()
ensures that, unless size() < 2
, front.size()
and back.size()
do not differ by more than a factor of . In particular, and .
Next, we analyze the cost of add(i, x)
, ignoring the cost of calls to balance()
. If i <
...
Create a free account to access the full course.
By signing up, you agree to Educative's Terms of Service and Privacy Policy