CSE 11 Computer Science 1 Module 9a: ADT Representations Stack and queue ADTs array implementations Buffer ADT and circular lists
Buffer ADT add and remove from both ends»can grow and shrink from either end»cannot access middle, e.g. find(p)»may wrap in either direction first 4 6 6 count=4 This yields buffer ADT, also sometimes called a doubleended queue (or deque, which is pronounced deck ) Operations include»getfirst(), getlast()»addfirst(x), addlast(x),»removefirst(), removelast() Again, constant time per operation»note, not true if we just used ArrayList in place of Buffer
The Stack Abstract Data Type A stack is a data structure that stores a collection of items and supports the following operations»push(x) add item x onto the top of the stack»pop() remove the item currently on top of the stack»peek() return the item that is currently at the top of the stack peek()= push() push(0) 0 pop»sequence: push(x), then i pushes, then i pops gives peek()=x Special case of the List ADT so why bother?»often easier to understand (and correctly implement) programs that use just the right data structure restrictions reduce bugs»specialized versions can be implemented more efficiently
The Queue Abstract Data Type A queue is a data structure that stores a collection of items and supports the following operations»enqueue(x) add item x to the tail of the queue»peek() return the item that is at the head of the queue»dequeue() remove the item at the head of the queue peek()= enqueue(6) dequeue() 6 6»sequence: enqueue(x), enqueue(y) is eventually followed by peek()=x and next dequeue() yields peek()=y»queues often used to link multiple stages of a computation 4
Implement Buffer, Stack, Queue using List Suppose you have a List that implements»getfirst(), getlast()»addfirst(x), addlast(x),»removefirst(), removelast() We can implement a buffer by simple passing-through addlast(object x) { list.addlast(x); We do not expose other details of the List to the buffer Stack: push addfirst(), peek getfirst(), pop removefirst() Queue: enqueue addlast(), peek getfirst(), dequeue removefirst()
Array-Based Stack Implementation Array implementation of stacks is simple and efficient»instance variable top stores index of top element»peek() returns stackarray[top]»push(x): stackarray[++top]=x»pop(): top»add tests to avoid overflow/underflow»isempty() returns (top == 1) Constant time per operation»that is, pushing an item onto a stack with a million items takes same time as for a stack with two items»true because items only added/removed at top of stack In Java, stacks of objects store objects separately from the array top 1 0 1 0 stackarray abc def xyz 6
Array-Based Queue Implementation Array implementation of queue is simple and efficient»instance variable head points to first item in queue; tail points to item»count is # of elements in the queue»head and tail wrap around at end of array»peek() returns qarray[head]»enqueue(x): tail=(tail+1)%size; qarray[tail]=x»dequeue(): head=(head+1)%size Again, constant time per operation since items are only added/removed from ends Queues of objects store objects separately from the array head 4 6 tail 6 count=4 tail head 0 1 8 1 4 8 count=4
Comparing ADT Implementations Stack Queue Buffer ArrayList LinkedList getfirst X constant constant constant constant getlast constant X constant constant constant addfirst X X constant linear constant addlast constant constant constant constant constant removefirst X constant constant linear constant removelast constant X constant constant constant add anywhere X X X linear constant remove any item X X X linear constant access by position X X X constant linear Constant means time is independent of # of elements Linear means time grows in proportion to # of elements in the worst-case 8
Circular Lists Array-based implementations require allocating space when data structure is constructed»often, don t know how much space is needed in advance»linked lists allow stacks/queues/buffers to grow and shrink as needed Circular lists are a natural choice for stacks/queues»usually implemented with pointer to item»makes addfirst(), addlast(), removefirst() easy»removelast() requires going all the way around (or does it?) 1 1 4 4 4 addlast(8) removefirst() 9
public class CircularList(){ public ListItem ; public void addlast(int x){ if( == null) { = new ListItem(x, null);.next = ; else {.next = new ListItem(x,.next); =.next; 8 addlast(8) 10
public void addfirst(int x){ if( == null) { = new ListItem(x, null);.next = ; else {.next = new ListItem(x,.next); 8 addfirst(8) 11
public int getfirst(){ if( == null) throw new EmptyException(); return.next.value; public int removefirst() { int x = getfirst();.next =.next.next; return x; 8 8 getfirst() is removefirst() 1
Implement Stack using Circular List public class Stack { private CircularList elements = new CircularList(); public void push(x) {elements.addfirst(x); public int pop() {return elements.removefirst(); public int peek() {return elements.getfirst(); 1
Implement Queue using Circular List public class Queue { private CircularList elements = new CircularList(); public void enqueue(x) {elements.addlast(x); public int dequeue) { return elements.removefirst(); public int peek() {return elements.getfirst(); 14