Dynamic Array Queue

Download Report

Transcript Dynamic Array Queue

CS 261- Winter 2011
Dynamic Array Queue and Deque
Dynamic Array Review
• Last lecture we introduced the dynamic
array
• Benefits: Can be randomly accessed
just like an array, grows as needed
• End user unaware of memory
management issues (buffer reallocation
when more space is needed)
you can build a Stack with a
dynamic array
• Stack is easy with a dynamic array (add
and remove elements from top end)
• Only complication is occasional buffer
increase
• So O(1) remove, O(n) worst case
insertion, but O(1) expected
• Latter often written as O(1)+
You can build a Bag with a
dynamic array
• Building a bag is only slightly more
complicated. Since order is unimportant,
adding to end is easy
• Remove requires moving everything
above the location down
• Add O(1)+, test: O(n), remove: O(n)
Picture of removal
What about building a queue?
• Recall queue is a collection where
elements are inserted at one end,
removed from another (think of queue of
people waiting at a door)
• Which end makes most sense for
insertion? For removal?
• What would be the O(?) ?
Removing from front
2
4
7
3
9
4
7
3
9
1
1
Inserting to front
2
4
7
3
9
4
7
3
9
1
1
What about a Deque
• Actually, easier to generalize the
structure in this case to a Deque
• Deque - Double Ended Queue (or
maybe Double Ended Staque…)
• Allows (efficient) insertions at both front
and back
• Lets see how we can do this
Key idea
• Key idea: Don’t tie “front” to location
zero
• Instead, allow both “front” and “back” to
float around the array
Picture of array
Adding to either end
• Add to front - back off starting point by
one
• Add to back - increase size by one
• Remove just the opposite
• There is just one small problem, what if
elements wrap around?
Picture of wrapping around
DataSize = 6
DataStart = 7
Data =
9
1
2
4
7
3
How to handle wrapping
• When making new index position, if less
than zero add capacity to number
• If larger than capacity, subtract capacity
from number
• If size reaches capacity, reallocate new
buffer as before (I’ve done this for you
in the worksheet).
Or use mod operator
• Some people prefer to use mod
operator:
endIndex = (da->start + da->size);
If (endIndex > da->capacity) endIndex -= da->capacity;
Versus
endIndex = (da->start + da->size) % da->capacity;
Readability is in the eye of the beholder, either one
works.
Keeping size vs
Keeping pointer to end
• Notice we compute the end by keeping
index of front and size
• Why not keep index of end?
• Would work, but then would have to
compute size. Slightly less computation
doing it the way we have it here.
Some of the code I give you
struct deque {
EleType * data;
int capacity;
int size;
int start;
};
init
void dequeInit (struct deque *d, int initCapacity) {
d->size = d->start = 0;
d->capacity = initCapacity;
assert(initCapacity > 0);
d->data = (EleType *)
malloc(initCapacity * sizeof(EleType));
assert(d->data != 0);
}
Double Capacity
void _dequeDoubleCapacity (struct deque *d) {
EleType * oldData = d->data;
int i = d->start;
int j;
int oldSize = d->size;
int oldCapacity = d->capacity;
dequeInit(d, 2 * oldCapacity);
for (j = 0 ; j < oldSize; j++) {
d->data[j] = oldData[i++];
if (i >= oldCapacity) i = 0;
}
free(oldData);
d->size = oldSize;
}
Your turn
• Write the code for Dynamic Array
Deque
• Lets think about this. How do you
– add to front? Add to back?
– Return front? Return back?
– Remove front? Remove back?