Abstract Data Types Queue + Dequeue Amortized analysis

1 / 50

# Abstract Data Types Queue + Dequeue Amortized analysis - PowerPoint PPT Presentation

Abstract Data Types Queue + Dequeue Amortized analysis. 5 4 17 21. Q. 5 4 17 21. Can one Implement A Queue with stacks?. You are given the STACK ABSTRACT data structure (1, 2 .. as many as you want) Can you use it to implement a queue. S 2. S 1. Implementation of Queue with stacks.

I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.

## PowerPoint Slideshow about 'Abstract Data Types Queue + Dequeue Amortized analysis' - lilli

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

### Abstract Data TypesQueue + DequeueAmortized analysis

5 4 17 21

Q

5 4 17 21

Can one Implement A Queue with stacks?
• You are given the STACK ABSTRACT data structure (1, 2 .. as many as you want)
• Can you use it to implement a queue

S2

S1

Implementation of Queue 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 of a Queue 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 this tight ?
Key Observation
• An expensive operation cannot occur too often !

2

7

5 4

21

S1

S2

Amortized complexity

THM: If we start with an empty queue and perform m operations then it takes O(m) time

Proof:

• No element moves from S2 to S1
• Entrance at S1, exit at S2.
• Every element:
• Enters S1 exactly once
• Moves from S1 to S2 at most once
• Exits S2 at most once
•  #ops per element ≤ 3
• m operations  #elements ≤ m  work ≤ 3 m
Potential based Proof (on your own)

Consider

Think of Φ as accumulation of easy operations covering for future potential “damage”

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

tail

size=2

13

5

Empty list

tail

size=0

We use two sentinels here to make the code simpler

Push

tail

size=1

5

push(x,D): n = new node

n.element ←x

size ← size + 1

4

tail

size=1

5

push(x,D): n = new node

n.element ←x

size ← size + 1

push(4,D)

4

tail

size=1

5

push(x,D): n = new node

n.element ←x

size ← size + 1

push(4,D)

4

tail

size=1

5

push(x,D): n = new node

n.element ←x

size ← size + 1

push(4,D)

4

tail

size=2

5

push(x,D): n = new node

n.element ←x

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
Thm: If we start with an empty deque and perform m operations then it takes O(m) time
A better bound

Consider

Think of Φ as accumulation of easy operations covering for future potential “damage”

Recall that: Amortized(op) = actual(op) + ΔΦ

This is O(1) if no splitting occurs

Say we split S1:

Then the actual time is |S1| + O(1)

ΔΦ = -|S1| (S2 empty)

So the amortized time is O(1)