1.13k likes | 1.15k Views
This article explains the abstract data types (ADTs) Stack and Queue, their application, implementation, and efficiency analysis using arrays and linked lists.
E N D
ADT is an interface • It defines • the type of the data stored • operations, what each operation does (not how) • parameters of each operation
ADT Application חוזה בין מתכנת האפליקציה ומיישם מבנה הנתונים ממשק Implementation of the Data structure
Example: Stacks • Push(x,S) : Insert element x into S • Pop(S) : Delete the last element inserted into S • Empty?(S): Return yes if S is empty • Top(S): Return the last element inserted into S • Size(S) • Make-stack()
push push push The Stack Data Abstraction
push The Stack Data Abstraction push push Last in, First out. push pop
A stack application InfixPostfix (2+ 3) * 5 2 3 + 5 * ( (5 * (7 / 3) ) – (2 * 7) ) 5 7 3 / * 2 7 *- • Evaluate an expression in postfix or Reverse Polish Notation
A stack application 2 3 + 5 * 3 2
A stack application 2 3 + 5 * 5 5
A stack application 2 3 + 5 * 25
Pseudo-code S ← make-stack() while ( not eof ) do B ← read the next data; if B is an operand thenpush(B,S) else X ← pop(S) Y ← pop(S) Z ← Apply the operation B on X and Y push(Z,S) return(top(S))
Implementation • We will be interested in algorithms to implement the ADT.. • And their efficiency..
Using an array t 12 1 3 A A[2] A[1] A[N-1] A[0] The stack is represented by the array A and variable t 3 1 12
Using an array t 12 1 3 A A[2] A[1] A[N-1] A[0] The stack is represented by the array A and variable t make-stack(): Allocates the array A, which is of some fixed size N, sets t ← -1
Operations t 12 1 3 A A[2] A[1] A[N-1] A[0] size(S): return (t+1) empty?(S): return (t < 0) top(S): ifempty?(S) then error else return A[t]
Pop t 12 1 3 A A[2] A[1] A[N-1] A[0] pop(S): ifempty?(S) then error else e ←A[t] t ← t – 1 return (e) pop(S)
Pop t 12 1 3 A A[2] A[1] A[N-1] A[0] pop(S): ifempty?(S) then error else e ←A[t] t ← t – 1 return (e) pop(S)
Push t 12 1 3 A A[2] A[1] A[N-1] A[0] push(x,S): ifsize(S) = N then error else t ←t+1 A[t] ← x push(5,S)
Push t 12 1 5 A A[2] A[1] A[N-1] A[0] push(x,S): ifsize(S) = N then error else t ←t+1 A[t] ← x push(5,S)
x x.next x.element Implementation with lists top size=3 5 1 12
Implementation with lists top size=3 5 1 12 make-stack(): top ← null size ← 0
Operations top size=3 5 1 12 size(S): return (size) empty?(S): return (top = null) top(S): ifempty?(S) then error else return top.element
Pop top size=3 5 1 12 pop(S): ifempty?(S) then error else e ←top.element top ← top.next size ← size-1 return (e) pop(S)
Pop top size=2 5 1 12 pop(S): ifempty?(S) then error else e ←top.element top ← top.next size ← size-1 return (e) pop(S)
Garbage collection top size=2 5 1 pop(S): ifempty?(S) then error else e ←top.element top ← top.next size ← size-1 return (e) pop(S)
Push top size=2 5 1 push(x,S): n = new node n.element ←x n.next ← top top ← n size ← size + 1 push(5,S)
Push top size=2 5 1 5 push(x,S): n = new node n.element ←x n.next ← top top ← n size ← size + 1 push(5,S)
Push top size=2 5 1 5 push(x,S): n = new node n.element ←x n.next ← top top ← n size ← size + 1 push(5,S)
Push top size=3 5 1 5 push(x,S): n = new node n.element ←x n.next ← top top ← n size ← size + 1 push(5,S)
Analysis • Bound the running time of an operation on the worst-case • As a function of the “size”, n, of the data structure • T(n) < 4n+7 • Too detailed, we are just interested in the order of growth
Big-O - קיים cו- כך ש: דוגמא:
cg(n) f(n) n0 Big-O
The running time of our stack and queue operations • Each operation takes O(1) time
Stacks via extendable arrays • We do not want our implementation using arrays to be limited to only N elements • When the array is full we will double its size
Push t 12 1 A A[1] A[N-1] A[0] push(x,S): ifsize(S) = N then {allocate a new array of size 2N copy the old array to the new one; N ← 2N } t ←t+1 A[t] ← x
Push t 12 1 3 3 4 5 7 3 2 8 1 A A[1] A[N-1] A[0] push(x,S): ifsize(S) = N then {allocate a new array of size 2N copy the old array to the new one; N ← 2N } t ←t+1 A[t] ← x push(5,S)
Push t 12 1 3 3 4 5 7 3 2 8 1 A A[1] A[0] push(x,S): ifsize(S) = N then {allocate a new array of size 2N copy the old array to the new one; N ← 2N } t ←t+1 A[t] ← x push(5,S)
Push 12 1 3 3 4 5 7 3 2 8 1 t 12 1 3 3 4 5 7 3 2 8 1 A A[1] A[0] push(x,S): ifsize(S) = N then {allocate a new array of size 2N copy the old array to the new one; N ← 2N } t ←t+1 A[t] ← x push(5,S)
Push t 12 1 3 3 4 5 7 3 2 8 1 A A[1] A[2N-1] A[0] push(x,S): ifsize(S) = N then {allocate a new array of size 2N copy the old array to the new one; N ← 2N } t ←t+1 A[t] ← x push(5,S)
Push t 12 1 3 3 4 5 7 3 2 8 1 5 A A[1] A[2N-1] A[0] push(x,S): ifsize(S) = N then {allocate a new array of size 2N copy the old array to the new one; N ← 2N } t ←t+1 A[t] ← x push(5,S)
Analysis • An operation may take O(n) worst case time ! • But that cannot happen often..
Amortized Analysis • How long it takes to do m operations in the worst case ? • Well, O(nm) • Yes, but can it really take that long ?
x x
x x x x x
x x x x x x
x x x x x x x x x x x
x x x x x x x x x x x x
x x x x x x x x x x x x x