Abstract Data Types EECS 214, Fall 2017
What is an ADT? An ADT defjnes: An ADT omits: How the values are concretely represented How the operations work 2 • A set of (abstract) values • A set of (abstract) operations on those values
What is an ADT? An ADT defjnes: An ADT omits: 2 • A set of (abstract) values • A set of (abstract) operations on those values • How the values are concretely represented • How the operations work
ADT: Stack Signature: push (Stack, Element): Void pop (Stack): Element isEmpty (Stack): Bool 3 Looks like: |3 4 5 �
ADT: Stack Signature: 3 Looks like: |3 4 5 � • push (Stack, Element): Void • pop (Stack): Element • isEmpty (Stack): Bool
ADT: Queue (FIFO) Signature: enqueue (Queue, Element): Void dequeue (Queue): Element isEmpty (Queue): Bool 4 Looks like: � 3 4 5 �
ADT: Queue (FIFO) Signature: 4 Looks like: � 3 4 5 � • enqueue (Queue, Element): Void • dequeue (Queue): Element • isEmpty (Queue): Bool
Stack versus Queue Stack signature: Queue signature: 5 • push (Stack, Element): Void • pop (Stack): Element • isEmpty (Stack): Bool • enqueue (Queue, Element): Void • dequeue (Queue): Element • isEmpty (Queue): Bool
Adding laws means that if precondition p is true when we apply f to x then we will get y as a result, and postcondition q will be true afterward. Examples: a a a a a a 6 { p } f ( x ) ⇒ y { q }
Adding laws means that if precondition p is true when we apply f to x then we will get y as a result, and postcondition q will be true afterward. Examples: 6 { p } f ( x ) ⇒ y { q } { a = [2 , 4 , 6 , 8] } a [2] ⇒ 6 { a = [2 , 4 , 6 , 8] } { a = [2 , 4 , 6 , 8] } a [2] = 0 { a = [2 , 4 , 0 , 8] }
ADT: Stack Signature: Laws: 7 Looks like: |3 4 5 � • push (Stack, Element): Void • pop (Stack): Element • isEmpty (Stack): Bool isEmpty ( |� ) ⇒ ⊤ isEmpty ( | e 1 . . . e k e k +1 � ) ⇒ ⊥ { s = | e 1 . . . e k �} push ( s , e ) { s = | e 1 . . . e k e �} { s = | e 1 . . . e k e k +1 �} pop ( s ) ⇒ e k +1 { s = | e 1 . . . e k �}
ADT: Queue (FIFO) Signature: Laws: 8 Looks like: � 3 4 5 � • enqueue (Queue, Element): Void • dequeue (Queue): Element • isEmpty (Queue): Bool isEmpty ( �� ) ⇒ ⊤ isEmpty ( � e 1 . . . e k e k +1 � ) ⇒ ⊥ { q = � e 1 . . . e k �} enqueue ( q , e ) { q = � e 1 . . . e k e �} { q = � e 1 e 2 . . . e k �} dequeue ( q ) ⇒ e 1 { q = � e 2 . . . e k �}
Stack implementation: linked list let s = new_stack() pop(s) pop(s) push(s, 5) push(s, 4) push(s, 3) push(s, 2) next data 2 data 5 next data 4 next data 3 head next 9
Stack implementation: linked list let s = new_stack() pop(s) pop(s) push(s, 5) push(s, 4) push(s, 3) push(s, 2) next data 2 data 5 next data 4 next data 3 head next 9
Stack implementation: linked list let s = new_stack() pop(s) pop(s) push(s, 5) push(s, 4) push(s, 3) push(s, 2) next data 2 data 5 next data 4 next data 3 head next 9
Stack implementation: linked list let s = new_stack() pop(s) pop(s) push(s, 5) push(s, 4) push(s, 3) push(s, 2) next data 2 data 5 next data 4 next data 3 head next 9
Stack implementation: linked list let s = new_stack() pop(s) pop(s) push(s, 5) push(s, 4) push(s, 3) push(s, 2) next data 2 data 5 next data 4 next data 3 head next 9
Stack implementation: linked list let s = new_stack() pop(s) pop(s) push(s, 5) push(s, 4) push(s, 3) push(s, 2) next data 2 data 5 next data 4 next data 3 head next 9
Stack implementation: linked list let s = new_stack() pop(s) pop(s) push(s, 5) push(s, 4) push(s, 3) push(s, 2) next data 2 data 5 next data 4 next data 3 head next 9
Stack implementation: array data len 0 let s = new_stack() 2 push(s, 2) 2 3 push(s, 3) 2 3 4 push(s, 4) 2 3 4 5 push(s, 5) push(s, 6) 10
Stack implementation: array data len 1 let s = new_stack() 2 push(s, 2) 2 3 push(s, 3) 2 3 4 push(s, 4) 2 3 4 5 push(s, 5) push(s, 6) 10
Stack implementation: array data len 2 let s = new_stack() 2 push(s, 2) 2 3 push(s, 3) 2 3 4 push(s, 4) 2 3 4 5 push(s, 5) push(s, 6) 10
Stack implementation: array data len 3 let s = new_stack() 2 push(s, 2) 2 3 push(s, 3) 2 3 4 push(s, 4) 2 3 4 5 push(s, 5) push(s, 6) 10
Stack implementation: array data len 4 let s = new_stack() 2 push(s, 2) 2 3 push(s, 3) 2 3 4 push(s, 4) 2 3 4 5 push(s, 5) push(s, 6) 10
Stack implementation: array data len 4 let s = new_stack() 2 push(s, 2) 2 3 push(s, 3) 2 3 4 push(s, 4) 2 3 4 5 push(s, 5) push(s, 6) 10
ADT: Stack Signature: Laws: 11 Looks like: |3 4 5 � • push (Stack, Element): Void — O (1) • pop (Stack): Element — O (1) • isEmpty (Stack): Bool — O (1) isEmpty ( |� ) ⇒ ⊤ isEmpty ( | e 1 . . . e k e k +1 � ) ⇒ ⊥ { s = | e 1 . . . e k �} push ( s , e ) { s = | e 1 . . . e k e �} { s = | e 1 . . . e k e k +1 �} pop ( s ) ⇒ e k +1 { s = | e 1 . . . e k �}
Trade-ofgs: linked list stack versus array stack whereas array stack has a fjxed size (or must reallocate) no (or rare) allocation 12 • Linked list stack only fjlls up when memory fjlls up, • Array stack has better constant factors: cache locality and • Array stack space usage is tighter; linked list is smoother
ADT: Queue (FIFO) Signature: Laws: 13 Looks like: � 3 4 5 � • enqueue (Queue, Element): Void — O (1) • dequeue (Queue): Element — O (1) • isEmpty (Queue): Bool — O (1) isEmpty ( �� ) ⇒ ⊤ isEmpty ( � e 1 . . . e k e k +1 � ) ⇒ ⊥ { q = � e 1 . . . e k �} enqueue ( q , e ) { q = � e 1 . . . e k e �} { q = � e 1 e 2 . . . e k �} dequeue ( q ) ⇒ e 1 { q = � e 2 . . . e k �}
Queue implementation: linked list? let q = new_queue() n ? dequeue(q) — enqueue(q, 5) enqueue(q, 4) enqueue(q, 3) enqueue(q, 2) next head data 5 next data 4 next data 3 next data 2 14
Queue implementation: linked list? let q = new_queue() n ? dequeue(q) — enqueue(q, 5) enqueue(q, 4) enqueue(q, 3) enqueue(q, 2) next head data 5 next data 4 next data 3 next data 2 14
Queue implementation: linked list? let q = new_queue() n ? dequeue(q) — enqueue(q, 5) enqueue(q, 4) enqueue(q, 3) enqueue(q, 2) next head data 5 next data 4 next data 3 next data 2 14
Queue implementation: linked list? let q = new_queue() n ? dequeue(q) — enqueue(q, 5) enqueue(q, 4) enqueue(q, 3) enqueue(q, 2) next head data 5 next data 4 next data 3 next data 2 14
Queue implementation: linked list? let q = new_queue() n ? dequeue(q) — enqueue(q, 5) enqueue(q, 4) enqueue(q, 3) enqueue(q, 2) next head data 5 next data 4 next data 3 next data 2 14
Queue implementation: linked list? let q = new_queue() n ? — dequeue(q) enqueue(q, 5) enqueue(q, 4) enqueue(q, 3) enqueue(q, 2) next head data 5 next data 4 next data 3 next data 2 14
Queue implementation: linked list? next enqueue(q, 5) enqueue(q, 4) enqueue(q, 3) enqueue(q, 2) let q = new_queue() data 5 head next data 4 next data 3 next data 2 14 dequeue(q) — O ( n ) ?
Queue implementation: array? data len 0 let q = new_queue() 2 enqueue(q, 2) 2 3 enqueue(q, 3) 2 3 4 enqueue(q, 4) 2 3 4 5 enqueue(q, 5) 3 4 5 s.dequeue() — n ??? 15
Queue implementation: array? data len 1 let q = new_queue() 2 enqueue(q, 2) 2 3 enqueue(q, 3) 2 3 4 enqueue(q, 4) 2 3 4 5 enqueue(q, 5) 3 4 5 s.dequeue() — n ??? 15
Queue implementation: array? data len 2 let q = new_queue() 2 enqueue(q, 2) 2 3 enqueue(q, 3) 2 3 4 enqueue(q, 4) 2 3 4 5 enqueue(q, 5) 3 4 5 s.dequeue() — n ??? 15
Queue implementation: array? data len 3 let q = new_queue() 2 enqueue(q, 2) 2 3 enqueue(q, 3) 2 3 4 enqueue(q, 4) 2 3 4 5 enqueue(q, 5) 3 4 5 s.dequeue() — n ??? 15
Queue implementation: array? data len 4 let q = new_queue() 2 enqueue(q, 2) 2 3 enqueue(q, 3) 2 3 4 enqueue(q, 4) 2 3 4 5 enqueue(q, 5) 3 4 5 s.dequeue() — n ??? 15
Queue implementation: array? enqueue(q, 4) n ??? — s.dequeue() 3 4 5 enqueue(q, 5) 2 3 4 5 2 3 4 data enqueue(q, 3) 2 3 enqueue(q, 2) 2 let q = new_queue() len 4 15
Queue implementation: array? data len 4 let q = new_queue() 2 enqueue(q, 2) 2 3 enqueue(q, 3) 2 3 4 enqueue(q, 4) 2 3 4 5 enqueue(q, 5) 3 4 5 15 s.dequeue() — O ( n ) ???
Queue impl.: linked list with tail pointer next dequeue(q) dequeue(q) enqueue(q, 5) enqueue(q, 4) enqueue(q, 3) enqueue(q, 2) let q = new_queue() data 2 head next data 3 next data 4 next data 5 tail 16
Queue impl.: linked list with tail pointer next dequeue(q) dequeue(q) enqueue(q, 5) enqueue(q, 4) enqueue(q, 3) enqueue(q, 2) let q = new_queue() data 2 head next data 3 next data 4 next data 5 tail 16
Queue impl.: linked list with tail pointer next dequeue(q) dequeue(q) enqueue(q, 5) enqueue(q, 4) enqueue(q, 3) enqueue(q, 2) let q = new_queue() data 2 head next data 3 next data 4 next data 5 tail 16
Queue impl.: linked list with tail pointer next dequeue(q) dequeue(q) enqueue(q, 5) enqueue(q, 4) enqueue(q, 3) enqueue(q, 2) let q = new_queue() data 2 head next data 3 next data 4 next data 5 tail 16
Recommend
More recommend