Title: Abstract Data Types Stack, Queue Amortized analysis
1Abstract Data TypesStack, QueueAmortized
analysis
2Queue
- 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()
3The Queue Data Abstraction
4The Queue Data Abstraction
inject
inject
First in, First out (FIFO).
pop
5Using an array
t
12
1
4
2
5
A
A1
A2
AN-1
A0
pop(Q)
6Using an array
t
1
4
2
5
A
A1
A2
AN-1
A0
pop(Q)
7Using an array
t
1
4
2
5
A
A1
A2
AN-1
A0
This would be inefficient if we insist that
elements span a prefix of the array
8Using an array
r
f
12
1
4
2
5
A
A1
A2
AN-1
A0
r
f
A
A1
A2
A0
Empty queue fr
9Using an array
r
f
12
1
4
2
5
A
A1
A2
AN-1
A0
pop(Q)
10Using an array
r
f
1
4
2
5
A
A1
A2
AN-1
A0
pop(Q)
inject(5,Q)
11Using an array
r
f
1
4
2
5
5
A
A1
A2
AN-1
A0
pop(Q)
inject(5,Q)
inject(5,Q)
12Using an array
r
f
1
4
2
5
5
5
A
A1
A2
AN-1
A0
pop(Q)
inject(5,Q)
inject(5,Q)
pop(Q)
pop(Q)
13Using an array
r
f
2
5
5
5
A
A1
A2
AN-1
A0
pop(Q)
inject(5,Q)
inject(5,Q)
pop(Q)
pop(Q)
pop(Q), inject(5,Q), pop(Q), inject(5,Q),.
14Using an array
r
f
5
5
5
5
A
A1
A2
AN-1
A0
pop(Q)
inject(5,Q)
inject(5,Q)
pop(Q)
pop(Q)
pop(Q), inject(5,Q), pop(Q), inject(5,Q),.
15Make the array circular
r
f
5
5
5
5
A
A1
A2
AN-1
A0
Pop(Q), inject(5,Q), pop(Q), inject(5,Q),.
16Operations
r
f
1
4
2
5
A
A1
A2
AN-1
A0
empty?(Q) return (f r)
top(Q) if empty?(Q) then error
else return Af
17Operations
r
f
1
4
2
5
A
A1
A2
AN-1
A0
size(Q) if (r gt f) then return (r-f)
else return N-(f-r)
18Operations
r
f
5
5
5
5
A
A1
A2
AN-1
A0
size(Q) if (r gt f) then return (r-f)
else return N-(f-r)
19Pop
r
f
1
4
2
5
A
A1
A2
A0
pop(Q) if empty?(Q) then error
else e ?Af f ? (f 1) mod
N return (e)
pop(Q)
20Pop
r
f
1
4
2
5
A
A1
A2
A0
pop(Q) if empty?(Q) then error
else e ?Af f ? (f 1) mod
N return (e)
pop(Q)
21Push
r
f
4
2
5
A
A1
A2
A0
inject(x,Q) if size(Q) N-1 then error
else Ar ? x
r ? (r1) mod N
inject(5,Q)
22Push
r
f
4
2
5
5
A
A1
A2
A0
inject(x,Q) if size(Q) N-1 then error
else Ar ? x
r ? (r1) mod N
inject(5,Q)
23Implementation with lists
head
size3
5
12
1
tail
inject(4,Q)
24Implementation with lists
head
size3
4
5
12
1
tail
inject(4,Q)
25Implementation with lists
head
size3
4
5
12
1
tail
inject(4,Q)
Complete the details by yourself
26Implementation with stacks
S2
S1
13
5 4 17 21
size5
inject(x,Q) push(x,S2) size ? size 1
inject(2,Q)
27Implementation with stacks
S2
S1
13
5 4 17 21 2
size5
inject(x,Q) push(x,S2) size ? size 1
inject(2,Q)
28Implementation with stacks
S2
S1
13
5 4 17 21 2
size6
inject(x,Q) push(x,S2) size ? size 1
inject(2,Q)
29Pop
S2
S1
5 4 17 21 2
13
size6
pop(Q) if empty?(Q) error if
empty?(S1) then move(S2, S1) pop(
S1) size ? size -1
pop(Q)
30Pop
S2
S1
5 4 17 21 2
size6
pop(Q) if empty?(Q) error if
empty?(S1) then move(S2, S1) pop(
S1) size ? size -1
pop(Q)
31Pop
S2
S1
5 4 17 21 2
size5
pop(Q) if empty?(Q) error if
empty?(S1) then move(S2, S1) pop(
S1) size ? size -1
pop(Q)
pop(Q)
32Pop
S2
S1
5 4 17 21
2
size5
pop(Q) if empty?(Q) error if
empty?(S1) then move(S2, S1) pop(
S1) size ? size -1
pop(Q)
pop(Q)
33Pop
S2
S1
5 4 17
2
21
size5
pop(Q) if empty?(Q) error if
empty?(S1) then move(S2, S1) pop(
S1) size ? size -1
pop(Q)
pop(Q)
34Pop
S2
S1
5 4
2
21
17
size5
pop(Q) if empty?(Q) error if
empty?(S1) then move(S2, S1) pop(
S1) size ? size -1
pop(Q)
pop(Q)
35Pop
S2
S1
5
2
21
17
4
size5
pop(Q) if empty?(Q) error if
empty?(S1) then move(S2, S1) pop(
S1) size ? size -1
pop(Q)
pop(Q)
36Pop
S2
S1
2
21
17
4
5
size5
pop(Q) if empty?(Q) error if
empty?(S1) then move(S2, S1) pop(
S1) size ? size -1
pop(Q)
pop(Q)
37Pop
S2
S1
2
21
17
4
size4
pop(Q) if empty?(Q) error if
empty?(S1) then move(S2, S1) pop(
S1) size ? size -1
pop(Q)
pop(Q)
38move(S2, S1) while not empty?(S2) do
x ? pop(S2) push(x,S1)
39Analysis
- O(n) worst case time per operation
40Amortized Analysis
- How long it takes to perform m operations on the
worst case ? - O(nm)
- Is tha tight ?
41Key Observation
- An expensive operation cannot occur too often !
42- THM If we start with an empty queue and perform
m operations then it takes O(m) time
43The potential formalism
- The potential is in fact the bank
44Define a potential function ?
Define
Amortized(op) actual(op) ??
45Amortized(op1) actual(op1) ?1- ?0
Amortized(op2) actual(op2) ?2- ?1
Amortized(opn) actual(opn) ?n- ?(n-1)
?iAmortized(opi) ?iactual(opi) ?n- ?0
?iAmortized(opi) ? ?iactual(opi) if ?n- ?0 ? 0
46Proof
Recall that Amortized(op) actual(op) ?F
This is O(1) if a move does not occur
Say we move S2
Then the actual time is S2 O(1) ?F -S2
So the amortized time is O(1)
47Conclusion
- THM If we start with an empty queue and perform
m operations then it takes O(m) time
48Double 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()
49Implementation with doubly linked lists
head
tail
size2
13
5
50Empty list
head
tail
size0
We use two sentinels here to make the code simpler
51Push
head
tail
size1
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
52head
tail
size1
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)
53head
tail
size1
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)
54head
tail
size1
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)
55head
tail
size2
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)
56Implementations of the other operations are
similar
57Back to deques
- Alternative implementation using stacks
58Implementation with stacks
S2
S1
13
5 4 17 21
size5
push(x,D) push(x,S1)
push(2,D)
59Implementation with stacks
S2
S1
2 13
5 4 17 21
size6
push(x,D) push(x,S1)
push(2,D)
60Pop
S2
S1
2 13
5 4 17 21
size6
pop(D) if empty?(D) error if
empty?(S1) then split(S2, S1) pop(
S1)
pop(D)
61Pop
S2
S1
13
5 4 17 21
size5
pop(D) if empty?(D) error if
empty?(S1) then split(S2, S1) pop(
S1)
pop(D)
pop(D)
62Pop
S2
S1
5 4 17 21
size4
pop(D) if empty?(D) error if
empty?(S1) then split(S2, S1) pop(
S1)
pop(D)
pop(D)
63Pop
S2
S1
5 4 17 21
size4
pop(D) if empty?(D) error if
empty?(S1) then split(S2, S1) pop(
S1)
pop(D)
64Pop
S2
S1
5 4 17 21
size4
pop(D) if empty?(D) error if
empty?(S1) then split(S2, S1) pop(
S1)
pop(D)
65Pop
S2
5 4
S1
17 21
size4
pop(D) if empty?(D) error if
empty?(S1) then split(S2, S1) pop(
S1)
pop(D)
66Pop
S2
S1
17 21
4
size4
pop(D) if empty?(D) error if
empty?(S1) then split(S2, S1) pop(
S1)
pop(D)
67Pop
S2
S1
17 21
4
size3
pop(D) if empty?(D) error if
empty?(S1) then split(S2, S1) pop(
S1)
pop(D)
68Split
S2
S1
5 4 17 21
S3
69Split
S2
S1
5 4 17
S3
21
70Split
S2
S1
5 4
S3
17
21
71Split
S2
S1
5
4
S3
17
21
72Split
S2
S1
5
4
S3
17
21
73Split
S2
S1
17
5
4
S3
21
74Split
S2
S1
21
17
5
4
S3
75split(S2, S1) S3 ? make-stack() d ?
size(S2) while (i ?d/2?) do x ?
pop(S2) push(x,S3) i ? i1 while (i
?d/2?) do x ? pop(S2) push(x,S1) i ?
i1 while (i ?d/2?) do x ?
pop(S3) push(x,S2) i ? i1
76Analysis
- O(n) worst case time per operation
77- Thm If we start with an empty deque and perform
m operations then its takes O(m) time
78Amortized Analysis
- How long it takes to perform m operations on the
worst case ? - O(nm)
- Really ?
79Key Observation
- An expensive operation cannot occur too often !
80A better bound
Recall that Amortized(op) actual(op) ?F
This is O(1) if no splitting occurs
Say we split S1
Then the actual time is S1 O(1) ?F -S1
So the amortized time is O(1)