520 likes | 526 Views
Abstract Data Types Stack, Queue Amortized analysis. Queue. Inject(x,Q) : Insert last element x into Q Pop(Q) : Delete the first element in Q Empty?(Q): Return yes if Q is empty Front(Q): Return the first element in Q Size(Q) Make-queue(). Implementation with lists. head. size=3.
E N D
Queue • Inject(x,Q) : Insert lastelement x into Q • Pop(Q) : Delete the first element in Q • Empty?(Q): Return yes if Q is empty • Front(Q): Return the first element in Q • Size(Q) • Make-queue()
Implementation with lists head size=3 5 1 12 tail inject(4,Q)
Implementation with lists head size=3 4 5 1 12 tail inject(4,Q)
Implementation with lists head size=3 4 5 1 12 tail inject(4,Q) Complete the details by yourself
Implementation with stacks S2 S1 13 5 4 17 21 size=5 inject(x,Q): push(x,S2); size ← size + 1 inject(2,Q)
Implementation with stacks S2 S1 13 5 4 17 21 2 size=5 inject(x,Q): push(x,S2); size ← size + 1 inject(2,Q)
Implementation with stacks S2 S1 13 5 4 17 21 2 size=6 inject(x,Q): push(x,S2); size ← size + 1 inject(2,Q)
Pop S2 S1 13 5 4 17 21 2 size=6 pop(Q): if empty?(Q) error if empty?(S1) then move(S2, S1) pop( S1); size ← size -1 pop(Q)
Pop S2 S1 5 4 17 21 2 size=6 pop(Q): if empty?(Q) error if empty?(S1) then move(S2, S1) pop( S1); size ← size -1 pop(Q)
Pop S2 S1 5 4 17 21 2 size=5 pop(Q): if empty?(Q) error if empty?(S1) then move(S2, S1) pop( S1); size ← size -1 pop(Q) pop(Q)
Pop S2 S1 2 5 4 17 21 size=5 pop(Q): if empty?(Q) error if empty?(S1) then move(S2, S1) pop( S1); size ← size -1 pop(Q) pop(Q)
Pop S2 S1 2 5 4 17 21 size=5 pop(Q): if empty?(Q) error if empty?(S1) then move(S2, S1) pop( S1); size ← size -1 pop(Q) pop(Q)
Pop S2 S1 2 17 5 4 21 size=5 pop(Q): if empty?(Q) error if empty?(S1) then move(S2, S1) pop( S1); size ← size -1 pop(Q) pop(Q)
Pop S2 S1 4 2 17 5 21 size=5 pop(Q): if empty?(Q) error if empty?(S1) then move(S2, S1) pop( S1); size ← size -1 pop(Q) pop(Q)
Pop S2 S1 4 2 5 17 21 size=5 pop(Q): if empty?(Q) error if empty?(S1) then move(S2, S1) pop( S1); size ← size -1 pop(Q) pop(Q)
Pop S2 S1 4 2 17 21 size=4 pop(Q): if empty?(Q) error if empty?(S1) then move(S2, S1) pop( S1); size ← size -1 pop(Q) pop(Q)
move(S2, S1) while not empty?(S2) do x ←pop(S2) push(x,S1)
Analysis • O(n) worst case time per operation
Amortized Analysis • How long it takes to perform m operations on the worst case ? • O(nm) • Is tha tight ?
Key Observation • An expensive operation cannot occur too often !
THM: If we start with an empty queue and perform m operations then it takes O(m) time
Proof Consider Recall that: Amortized(op) = actual(op) + ΔΦ This is O(1) if a move does not occur Say we move S2: Then the actual time is |S2| + O(1) ΔΦ = -|S2| So the amortized time is O(1)
Double ended queue (deque) • Push(x,D) : Insert x as the first in D • Pop(D) : Delete the first element of D • Inject(x,D): Insert x as the last in D • Eject(D): Delete the last element of D • Size(D) • Empty?(D) • Make-deque()
x x.next x.prev x.element Implementation with doubly linked lists head tail size=2 13 5
Empty list head tail size=0 We use two sentinels here to make the code simpler
Push head tail size=1 5 push(x,D): n = new node n.element ←x n.next ← head.next (head.next).prev ← n head.next ← n n.prev← head size ← size + 1
4 head tail size=1 5 push(x,D): n = new node n.element ←x n.next ← head.next (head.next).prev ← n head.next ← n n.prev← head size ← size + 1 push(4,D)
4 head tail size=1 5 push(x,D): n = new node n.element ←x n.next ← head.next (head.next).prev ← n head.next ← n n.prev← head size ← size + 1 push(4,D)
4 head tail size=1 5 push(x,D): n = new node n.element ←x n.next ← head.next (head.next).prev ← n head.next ← n n.prev← head size ← size + 1 push(4,D)
4 head tail size=2 5 push(x,D): n = new node n.element ←x n.next ← head.next (head.next).prev ← n head.next ← n n.prev← head size ← size + 1 push(4,D)
Implementation with stacks S2 S1 13 5 4 17 21 size=5 push(x,D): push(x,S1) push(2,D)
Implementation with stacks S2 S1 2 13 5 4 17 21 size=6 push(x,D): push(x,S1) push(2,D)
Pop S2 S1 2 13 5 4 17 21 size=6 pop(D): if empty?(D) error if empty?(S1) then split(S2, S1) pop( S1) pop(D)
Pop S2 S1 13 5 4 17 21 size=5 pop(D): if empty?(D) error if empty?(S1) then split(S2, S1) pop( S1) pop(D) pop(D)
Pop S2 S1 5 4 17 21 size=4 pop(D): if empty?(D) error if empty?(S1) then split(S2, S1) pop( S1) pop(D) pop(D)
Pop S2 S1 5 4 17 21 size=4 pop(D): if empty?(D) error if empty?(S1) then split(S2, S1) pop( S1) pop(D)
Pop S2 S1 5 4 17 21 size=4 pop(D): if empty?(D) error if empty?(S1) then split(S2, S1) pop( S1) pop(D)
Pop S2 5 4 S1 17 21 size=4 pop(D): if empty?(D) error if empty?(S1) then split(S2, S1) pop( S1) pop(D)
Pop S2 S1 4 17 21 size=4 pop(D): if empty?(D) error if empty?(S1) then split(S2, S1) pop( S1) pop(D)
Pop S2 S1 4 17 21 size=3 pop(D): if empty?(D) error if empty?(S1) then split(S2, S1) pop( S1) pop(D)
Split S2 S1 5 4 17 21 S3
Split S2 S1 5 4 17 S3 21
Split S2 S1 5 4 S3 17 21
Split S2 S1 4 5 S3 17 21
Split S2 S1 5 4 S3 17 21
Split S2 S1 17 5 4 S3 21
Split S2 S1 17 21 5 4 S3
split(S2, S1) S3←make-stack() d ←size(S2) while (i ≤⌊d/2⌋) do x ←pop(S2) push(x,S3) i ← i+1 while (i ≤⌈d/2⌉) do x ←pop(S2) push(x,S1) i ← i+1 while (i ≤⌊d/2⌋) do x ←pop(S3) push(x,S2) i ← i+1
Analysis • O(n) worst case time per operation