Elementary Data Structures Elementary Data Structures n Stack

  • Slides: 68
Download presentation
Elementary Data Structures

Elementary Data Structures

Elementary Data Structures n Stack n n Queue n n container of elements that

Elementary Data Structures n Stack n n Queue n n container of elements that are inserted and removed last-in first-out (LIFO) container of elements that are inserted and removed first-in first-out (FIFO) Deque (double-ended queue) n container of elements that allows insertion and removal from either end L 8: Elem DS Slide 2

Stack n n Last-in, First-out (LIFO) structure Operations n n n push: add element

Stack n n Last-in, First-out (LIFO) structure Operations n n n push: add element into the stack pop: remove & return topmost element top: return topmost element is. Empty: check if the stack has no elements size: return number of elements in the stack Sample uses n “Back” button of a browser, “Undo” operation, function/method calls L 8: Elem DS Slide 3

Stack Interface public interface Stack { public int size(); public boolean is. Empty(); public

Stack Interface public interface Stack { public int size(); public boolean is. Empty(); public void push( Object o ); public Object top() throws Empty. Stack. Exception; public Object pop() throws Empty. Stack. Exception; } public class Empty. Stack. Exception extends Runtime. Exception { } L 8: Elem DS Slide 4

Array Implementation top 3 S public class Array. Stack implements Stack { private int

Array Implementation top 3 S public class Array. Stack implements Stack { private int top = -1; private Object S[]; . . . } . . . x z y w L 8: Elem DS Slide 5

Array Implementation Details n n An array of objects stores the elements An integer

Array Implementation Details n n An array of objects stores the elements An integer field points to the topmost element n n n Value of top is – 1 when the stack is empty A constant indicates the size/capacity of the array Throw a Stack. Full. Exception when a push is attempted on a full array L 8: Elem DS Slide 6

Array. Stack class public class Array. Stack implements Stack { public static final int

Array. Stack class public class Array. Stack implements Stack { public static final int CAPACITY = 1000; private Object S[]; private int top; public Array. Stack() { S = new Object[CAPACITY]; top = -1; } public boolean is. Empty() { return (top < 0); }… } L 8: Elem DS Slide 7

Array. Stack class continued public class Array. Stack implements Stack {… public int size()

Array. Stack class continued public class Array. Stack implements Stack {… public int size() { return (top + 1); } } public void push(Object obj) throws Full. Stack. Exception { if (size() == CAPACITY) throw new Full. Stack. Exception(); S[++top] = obj; public class Full. Stack. Exception } extends Runtime. Exception … { } L 8: Elem DS Slide 8

Array. Stack class continued public class Array. Stack implements Stack {… public Object top()

Array. Stack class continued public class Array. Stack implements Stack {… public Object top() throws Empty. Stack. Exception { if (is. Empty()) throw new Empty. Stack. Exception(); return S[top]; } public Object pop() throws Empty. Stack. Exception { if (is. Empty()) throw new Empty. Stack. Exception(); return S[top--]; }… } L 8: Elem DS Slide 9

Garbage collection n After a pop() operation, array still contains reference to popped element

Garbage collection n After a pop() operation, array still contains reference to popped element n n Succeeding push() operations will override such references but it is not certain whether pushes will occur after the pops Better to set the reference to null so that the object is garbage-collected when no longer in use L 8: Elem DS Slide 10

Improved pop() method public class Array. Stack implements Stack {… public Object pop() throws

Improved pop() method public class Array. Stack implements Stack {… public Object pop() throws Empty. Stack. Exception { Object elem; if (is. Empty()) throw new Empty. Stack. Exception(); elem = S[top]; S[top--] = null; // dereference S[top] for garbage collection. return elem; } … } L 8: Elem DS Slide 11

Using the Stack s 1 = new Array. Stack(); String temp; s 1. push(

Using the Stack s 1 = new Array. Stack(); String temp; s 1. push( "easy" ); s 1. push( "this" ); temp = (String) s 1. pop(); System. out. print( temp ); s 1. push( "is" ); s 1. push( "class" ); while ( !s 1. is. Empty() ) { temp = (String) s 1. pop(); System. out. print( " "+ temp } System. out. println(); OK because Strings are Objects Cast object to String ); L 8: Elem DS Slide 12

Stack of ints Stack s 2 = new Array. Stack(); s 2. push( 5

Stack of ints Stack s 2 = new Array. Stack(); s 2. push( 5 ); s 2. push( 2 ); s 2. push( 3 ); int num = (Integer) s 2. pop(); System. out. println( num ); Note: In previous Java versions, s 2. push( new Integer( 2 ) ); num = ( (Integer) s 2. pop() ). int. Value(); Allowed in Java 1. 5 because primitive type values are “auto-boxed” Cast object to Integer type (not int) L 8: Elem DS Slide 13

Time Complexity Analysis n n n push() : pop() : is. Empty() : size()

Time Complexity Analysis n n n push() : pop() : is. Empty() : size() : top(): O(1) O(1) L 8: Elem DS Slide 14

Array Implementation Alternative n n n Make top variable point to next available array

Array Implementation Alternative n n n Make top variable point to next available array position instead of actual topmost element top = 0 when empty top 4 top represents size S . . . x z y w L 8: Elem DS Slide 15

Problems with Array. Stack n n CAPACITY needs to be specified Consequences n n

Problems with Array. Stack n n CAPACITY needs to be specified Consequences n n n stack may fill up (when size() == MAX ) memory is wasted if actual stack consumption is way below maximum Need a more “dynamic” implementation L 8: Elem DS Slide 16

Linked List Implementation top null y z w A stack as a sequence of

Linked List Implementation top null y z w A stack as a sequence of nodes L 8: Elem DS Slide 17

The Node class public class Node { private Object element; private Node next; public

The Node class public class Node { private Object element; private Node next; public Node( Object e, Node n ) { element = e; next = n; } public Object get. Element() … public Node get. Next() … public void set. Element( Object new. Elem ) … public void set. Next( Node new. Next ) … } y L 8: Elem DS Slide 18

Linked List Implementation n Stack is represented by a Node reference (called top) n

Linked List Implementation n Stack is represented by a Node reference (called top) n n n This reference is null when stack is empty Top refers to the top element only but links in each node keep the elements together An integer field represents the number of elements in the stack L 8: Elem DS Slide 19

Node. Stack class public class Node. Stack implements Stack { private Node top; private

Node. Stack class public class Node. Stack implements Stack { private Node top; private int size; public Node. Stack() { top = null; size = 0; } public boolean is. Empty() { return (top == null); }… } L 8: Elem DS Slide 20

Node. Stack class continued public class Node. Stack implements Stack {… public int size()

Node. Stack class continued public class Node. Stack implements Stack {… public int size() { return size; } public void push( Object obj ) { Node v = new Node( obj, top ); top = v; size++; } … } L 8: Elem DS Slide 21

Push operation top size 3 null y z w L 8: Elem DS Slide

Push operation top size 3 null y z w L 8: Elem DS Slide 22

Push operation top size 3 null x y z w Create node L 8:

Push operation top size 3 null x y z w Create node L 8: Elem DS Slide 23

Push operation top size 4 null x y z w Update top and size

Push operation top size 4 null x y z w Update top and size L 8: Elem DS Slide 24

Node. Stack class continued public class Node. Stack implements Stack {… public Object top()

Node. Stack class continued public class Node. Stack implements Stack {… public Object top() throws Empty. Stack. Exception { if ( is. Empty() ) throw new Empty. Stack. Exception(); return top. get. Element(); } public Object pop() throws Empty. Stack. Exception { if ( is. Empty() ) throw new Empty. Stack. Exception(); Object temp = top. get. Element(); top = top. get. Next(); size--; return temp; }… } L 8: Elem DS Slide 25

Pop operation top size 4 null x y z w L 8: Elem DS

Pop operation top size 4 null x y z w L 8: Elem DS Slide 26

Pop operation top size 4 null x y z w temp Get top element

Pop operation top size 4 null x y z w temp Get top element L 8: Elem DS Slide 27

Pop operation top size 3 null x y z w temp Update top and

Pop operation top size 3 null x y z w temp Update top and size L 8: Elem DS Slide 28

Pop operation top size 3 null x y z w temp Node automatically disposed

Pop operation top size 3 null x y z w temp Node automatically disposed L 8: Elem DS Slide 29

Pop operation top size 3 null x y z w Return element L 8:

Pop operation top size 3 null x y z w Return element L 8: Elem DS Slide 30

Using the Node. Stack s 2 = new Node. Stack(); s 2. push( 5

Using the Node. Stack s 2 = new Node. Stack(); s 2. push( 5 ); s 2. push( 2 ); s 2. push( 3 ); int num = (Integer) s 2. pop(); System. out. println( num ); Only this line changed L 8: Elem DS Slide 31

Time Complexity Analysis n n n push() : pop() : is. Empty() : size()

Time Complexity Analysis n n n push() : pop() : is. Empty() : size() : top(): O(1) O(1) L 8: Elem DS Slide 32

Array. Stack versus Node. Stack n n Node. Stack uses only the memory that

Array. Stack versus Node. Stack n n Node. Stack uses only the memory that it needs at any given time Node. Stack has no size limit (just the system’s memory) – Full. Stack. Exception not thrown Array. Stack’s implementation is simpler Which implementation is more efficient? L 8: Elem DS Slide 33

Managing Multiple Implementations n Note that we now have two implementations of a Stack:

Managing Multiple Implementations n Note that we now have two implementations of a Stack: public class Array. Stack implements Stack {…} public class Node. Stack implements Stack {…} n Consider what code needs to be changed if we shift between implementations n It would be preferable if the code that uses the stack does not need to be updated L 8: Elem DS Slide 34

A Stack. Factory Class n Use a separate class that produces Stack objects public

A Stack. Factory Class n Use a separate class that produces Stack objects public class Stack. Factory { public static Stack create. Stack() { return new Array. Stack(); // or return new Node. Stack(); } } n Advantage: n n if you want to change your implementation, you just need to change Stack. Factory you don’t need to change all calls to new Array. Stack in all your code! L 8: Elem DS Slide 35

Using a Stack. Factory Stack s 2 = Stack. Factory. create. Stack(); s 2.

Using a Stack. Factory Stack s 2 = Stack. Factory. create. Stack(); s 2. push( 5 ); s 2. push( 2 ); this line need not be s 2. push( 3 ); changed even if the int num = (Integer) s 2. pop(); stack implementation changes System. out. println( num ); L 8: Elem DS Slide 36

Queue n n First-in, First-out (FIFO) structure Operations n n n enqueue: insert element

Queue n n First-in, First-out (FIFO) structure Operations n n n enqueue: insert element at rear dequeue: remove & return front element front: return front element is. Empty: check if the queue has no elements size: return number of elements in the queue Sample use n handling requests and reservations L 8: Elem DS Slide 37

The Queue Interface public interface Queue { public int size(); public boolean is. Empty();

The Queue Interface public interface Queue { public int size(); public boolean is. Empty(); public void enqueue( Object o ); public Object front() throws Empty. Queue. Exception; public Object dequeue() throws Empty. Queue. Exception; } public class Empty. Queue. Exception extends Runtime. Exception { } L 8: Elem DS Slide 38

Array Implementation Possibilities n On enqueue, place element in the next available slot; on

Array Implementation Possibilities n On enqueue, place element in the next available slot; on dequeue, remove element at position 0 and move all other elements to the left n n Dequeue takes O(n) time Have integer pointers to front and rear, increment rear on enqueue, increment front on dequeue, so that both operations are O(1) L 8: Elem DS Slide 39

Array Implementation of a Queue n An Object array and two integers n n

Array Implementation of a Queue n An Object array and two integers n n front: index of first element in queue rear: index of first FREE element in queue front 0 rear 4. . . L 8: Elem DS Slide 40

Array. Queue public class Array. Queue implements Queue { public static final int CAPACITY

Array. Queue public class Array. Queue implements Queue { public static final int CAPACITY = 1000; private Object s[]; private int front, rear; public Array. Queue() { s = new Object[CAPACITY]; front = rear = 0; }. . . } L 8: Elem DS Slide 41

is. Empty and Enqueue public class Array. Queue implements Queue {. . . public

is. Empty and Enqueue public class Array. Queue implements Queue {. . . public boolean is. Empty() { return ( front == rear ); } public void enqueue( Object o ) throws Full. Queue. Exception { if ( rear == CAPACITY ) throw new Full. Queue. Exception(); s[rear++] = o; }. . . public class Full. Queue. Exception extends Runtime. Exception } { } L 8: Elem DS Slide 42

Enqueue operation front 0 rear 3. . . L 8: Elem DS Slide 43

Enqueue operation front 0 rear 3. . . L 8: Elem DS Slide 43

Enqueue operation front 0 rear 4. . . Enqueued object L 8: Elem DS

Enqueue operation front 0 rear 4. . . Enqueued object L 8: Elem DS Slide 44

Dequeue public class Array. Queue implements Queue {. . . public Object dequeue() throws

Dequeue public class Array. Queue implements Queue {. . . public Object dequeue() throws Empty. Queue. Exception { if ( is. Empty() ) throw new Empty. Queue. Exception(); return s[front++]; } … } L 8: Elem DS Slide 45

Dequeue operation front 0 rear 4. . . L 8: Elem DS Slide 46

Dequeue operation front 0 rear 4. . . L 8: Elem DS Slide 46

Dequeue operation front 1 rear 4. . . Return this object L 8: Elem

Dequeue operation front 1 rear 4. . . Return this object L 8: Elem DS Slide 47

Dequeue operation Remember to set reference in array to null front 1 rear 4.

Dequeue operation Remember to set reference in array to null front 1 rear 4. . . L 8: Elem DS Slide 48

Dequeue with Garbage Collection public class Array. Queue implements Queue {. . . public

Dequeue with Garbage Collection public class Array. Queue implements Queue {. . . public Object dequeue() throws Empty. Queue. Exception { if ( is. Empty() ) throw new Empty. Queue. Exception(); Object data = s[front]; s[front] = null; front++; return data; } } L 8: Elem DS Slide 49

Circular Array n n n Suppose many enqueue operations followed by many dequeue operations

Circular Array n n n Suppose many enqueue operations followed by many dequeue operations Result: rear approaches CAPACITY but the queue is not really full Solution: Circular Array n allow rear (and front) to “wrap around” the array (if rear = CAPACITY-1, incrementing rear means resetting it to 0) L 8: Elem DS Slide 50

Circular Array, continued n When is the array full? n n n Solution: Reserve

Circular Array, continued n When is the array full? n n n Solution: Reserve a slot n n n Simple answer: when (rear == front) Problem: this is the same condition as empty full: when ( (rear+1) % CAPACITY == front) (one free slot left) empty: when ( rear == front ) Note: “wastes” a slot n n n alternative: have a boolean field called has. Elements full: when ( has. Elements && (rear == front)) But not really better n n has. Elements takes up extra space too Also, need to take care of has. Elements in enqueue and dequeue L 8: Elem DS Slide 51

Revised Enqueue public class Array. Queue implements Queue {. . . public void enqueue(

Revised Enqueue public class Array. Queue implements Queue {. . . public void enqueue( Object o ) throws Full. Queue. Exception { if ((rear+1) % CAPACITY == front) throw new Full. Queue. Exception(); s[rear] = o; rear = (rear + 1) % CAPACITY; }. . . } L 8: Elem DS Slide 52

Revised Dequeue public class Array. Queue implements Queue {. . . public Object dequeue()

Revised Dequeue public class Array. Queue implements Queue {. . . public Object dequeue() throws Empty. Queue. Exception { if ( is. Empty() ) throw new Empty. Queue. Exception(); Object data = s[front]; s[front] = null; front = (front + 1) % CAPACITY; return data; } … } L 8: Elem DS Slide 53

Completing the Dequeue class public class Array. Queue implements Queue {. . . public

Completing the Dequeue class public class Array. Queue implements Queue {. . . public int size() { return (CAPACITY + rear – front) % CAPACITY; } … public Object front() throws Empty. Queue. Exception { if ( is. Empty() ) throw new Empty. Queue. Exception(); return s[front]; } … } L 8: Elem DS Slide 54

Time Complexity Analysis n n n enqueue() : dequeue() : is. Empty() : size()

Time Complexity Analysis n n n enqueue() : dequeue() : is. Empty() : size() : front(): O(1) O(1) L 8: Elem DS Slide 55

Dynamic Implementation n Queue is represented by a linked sequence of nodes Two node

Dynamic Implementation n Queue is represented by a linked sequence of nodes Two node references refer to front and rear element, respectively Use a size field to monitor number of elements L 8: Elem DS Slide 56

Linked List Implementation front public class Node. Queue implements Queue { private Node front;

Linked List Implementation front public class Node. Queue implements Queue { private Node front; private Node rear; rear private int size; … } null L 8: Elem DS Slide 57

Enqueue front rear null L 8: Elem DS Slide 58

Enqueue front rear null L 8: Elem DS Slide 58

Dequeue front rear null return this object L 8: Elem DS Slide 59

Dequeue front rear null return this object L 8: Elem DS Slide 59

Node. Queue considerations n n n Exercise: complete the Node. Queue class Note that

Node. Queue considerations n n n Exercise: complete the Node. Queue class Note that the queue is empty when both front and rear are null Need to watch out for special cases n n Enqueue from an empty queue Dequeue from a single-element queue L 8: Elem DS Slide 60

Deque n n Data structure that allows insertion and deletion from either end of

Deque n n Data structure that allows insertion and deletion from either end of structure Operations n n n insert. First, insert. Last: add element remove. First, remove. Last: remove element first: return first element last: return last element is. Empty: check if the deque has no elements size: return number of elements in the deque L 8: Elem DS Slide 61

Deque Interface public interface Deque { public int size(); public boolean is. Empty(); public

Deque Interface public interface Deque { public int size(); public boolean is. Empty(); public void insert. First( Object o ); public void insert. Last( Object o ); public Object first() throws Empty. Deque. Exception; public Object last() throws Empty. Deque. Exception; public Object remove. First() throws Empty. Deque. Exception; public Object remove. Last() throws Empty. Deque. Exception; } public class Empty. Deque. Exception extends Runtime. Exception { } L 8: Elem DS Slide 62

Array Implementation of a Deque n n n Circular array implementation Integer pointers to

Array Implementation of a Deque n n n Circular array implementation Integer pointers to first and last element Insertion/removal operations n n n insert. First: decrement first pointer remove. First: increment first pointer insert. Last: increment last pointer remove. First: decrement last pointer Decide whether pointers should point to actual element or next available space n Impacts on full/empty conditions L 8: Elem DS Slide 63

Dynamic Implementation of a Deque n Linked List implementation first last null L 8:

Dynamic Implementation of a Deque n Linked List implementation first last null L 8: Elem DS Slide 64

Deque using a Singly Linked List n n insert. First, remove. First, insert. Last

Deque using a Singly Linked List n n insert. First, remove. First, insert. Last are O(1) operations remove. Last is an O(n) operation n Why? Need to update last pointer to point to second-to-the-last element How can we make all operations O(1)? n Have a link to next and previous nodes L 8: Elem DS Slide 65

Doubly Linked List first null last null L 8: Elem DS Slide 66

Doubly Linked List first null last null L 8: Elem DS Slide 66

The DLNode class public class DLNode { private Object element; private DLNode next, prev;

The DLNode class public class DLNode { private Object element; private DLNode next, prev; public Node( Object e, DLNode n, DLNode p ) { element = e; next = n; prev = p; } public Object get. Element() … public DLNode get. Next() … public DLNode get. Prev() … public void set. Element( Object new. Elem ) … public void set. Next( DLNode new. Next ) … public void set. Prev( DLNode new. Prev ) … } L 8: Elem DS Slide 67

Deque using a Doubly Linked List n insert. First, remove. First, insert. Last, remove.

Deque using a Doubly Linked List n insert. First, remove. First, insert. Last, remove. Last are O(1) operations n n Empty and single-element cases n n n Need to update next and prev pointers in DLNode Insertion from the empty case (both pointers are null) and removal from a single-element case (both point to the single element) need to be handled Or, make pointers point to dummy nodes (also called sentinels), so that insertion and removal need not worry about the special cases size field: as in singly-linked implementation, storing size makes is. Empty() and size() easier L 8: Elem DS Slide 68