Presentation is loading. Please wait.

Presentation is loading. Please wait.

1 Abstract Data Types Queue + Dequeue Amortized analysis.

Similar presentations


Presentation on theme: "1 Abstract Data Types Queue + Dequeue Amortized analysis."— Presentation transcript:

1 1 Abstract Data Types Queue + Dequeue Amortized analysis

2 2 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()

3 3 The Queue Data Abstraction inject

4 4 The Queue Data Abstraction inject pop First in, First out (FIFO).

5 5 Using an array 12142 A 5 A[0] A[1] t pop(Q) A[2] A[N-1]

6 6 Using an array 1425 A A[0] A[1] t pop(Q) A[2] A[N-1]

7 7 Using an array 1425 A A[0] A[1] t A[2] A[N-1] This would be inefficient if we insist that elements span a prefix of the array

8 8 Using an array 12142 A 5 A[0] A[1] r A[2] A[N-1] f A A[0] A[1] r A[2] f Empty queue f=r

9 9 Using an array 12142 A 5 A[0] A[1] r pop(Q) A[2] A[N-1] f

10 10 Using an array 142 A 5 A[0] A[1] A[2] A[N-1] f r pop(Q) inject(5,Q)

11 11 Using an array 142 A 55 A[0] A[1] A[2] A[N-1] f r pop(Q) inject(5,Q)

12 12 Using an array 142 A 555 A[0] A[1] A[2] A[N-1] f r pop(Q) inject(5,Q) pop(Q)

13 13 Using an array 2 A 555 A[0] A[1] A[2] A[N-1] f r pop(Q) inject(5,Q) pop(Q) pop(Q), inject(5,Q), pop(Q), inject(5,Q),……….

14 14 Using an array A 5555 A[0] A[1] r A[2] A[N-1] f pop(Q) inject(5,Q) pop(Q) pop(Q), inject(5,Q), pop(Q), inject(5,Q),……….

15 15 Make the array “circular” 5 5 A 55 A[0] A[1] r A[2] A[N-1] f Pop(Q), inject(5,Q), pop(Q), inject(5,Q),……….

16 16 Operations empty?(Q): return (f = r) top(Q): if empty?(Q) then error else return A[f] 142 A 5 A[0] A[1] A[2] A[N-1] f r

17 17 Operations size(Q): if (r >= f) then return (r-f) else return N-(f-r) 142 A 5 A[0] A[1] A[2] A[N-1] f r

18 18 Operations size(Q): if (r >= f) then return (r-f) else return N-(f-r) 5 5 A 55 A[0] A[1] r A[2] A[N-1] f

19 19 Pop pop(Q) 142 A 5 A[0] A[1] A[2] f r pop(Q): if empty?(Q) then error else e ← A[f] f ← (f + 1) mod N return (e)

20 20 Pop pop(Q): if empty?(Q) then error else e ← A[f] f ← (f + 1) mod N return (e) pop(Q) 142 A 5 A[0] A[1] A[2] f r

21 21 Push inject(x,Q): if size(Q) = N-1 then error else A[r] ← x r ← (r+1) mod N inject(5,Q) 42 A 5 A[0] A[1] A[2] f r

22 22 Push inject(x,Q): if size(Q) = N-1 then error else A[r] ← x r ← (r+1) mod N inject(5,Q) 42 A 55 A[0] A[1] A[2] f r

23 23 Implementation with lists 12 1 5 head size=3 tail inject(4,Q)

24 24 Implementation with lists 12 1 5 head size=3 tail inject(4,Q) 4

25 25 Implementation with lists 12 1 5 head size=3 tail inject(4,Q) 4 Complete the details by yourself

26 26 Can one Implement A Queue with stacks? S2S2 You are given the STACK ABSTRACT data structure (1, 2.. as many as you want) Can you use it to implement a queue S1S1 5 4 17 21 Q

27 27 Implementation of Queue with stacks size=5 13 S1S1 S2S2 inject(x,Q): push(x,S 2 ); size ← size + 1 5 4 17 21 inject(2,Q)

28 28 Implementation with stacks size=5 13 S1S1 S2S2 inject(x,Q): push(x,S 2 ); size ← size + 1 5 4 17 21 2 inject(2,Q)

29 29 Implementation of a Queue with stacks size=6 13 S1S1 S2S2 5 4 17 21 2 inject(2,Q) inject(x,Q): push(x,S 2 ); size ← size + 1

30 30 Pop size=6 S1S1 S2S2 pop(Q): if empty?(Q) error if empty?(S 1 ) then move(S 2, S 1 ) pop( S 1 ); size ← size -1 5 4 17 21 2 pop(Q) 13

31 31 Pop size=6 S1S1 S2S2 pop(Q): if empty?(Q) error if empty?(S 1 ) then move(S 2, S 1 ) pop( S 1 ); size ← size -1 5 4 17 21 2 pop(Q)

32 32 Pop size=5 S1S1 S2S2 pop(Q): if empty?(Q) error if empty?(S 1 ) then move(S 2, S 1 ) pop( S 1 ); size ← size -1 5 4 17 21 2 pop(Q) pop(Q)

33 33 Pop size=5 S1S1 S2S2 pop(Q): if empty?(Q) error if empty?(S 1 ) then move(S 2, S 1 ) pop( S 1 ); size ← size -1 5 4 17 21 pop(Q) pop(Q) 2

34 34 Pop size=5 S1S1 S2S2 pop(Q): if empty?(Q) error if empty?(S 1 ) then move(S 2, S 1 ) pop( S 1 ); size ← size -1 5 4 17 pop(Q) pop(Q) 2 21

35 35 Pop size=5 S1S1 S2S2 pop(Q): if empty?(Q) error if empty?(S 1 ) then move(S 2, S 1 ) pop( S 1 ); size ← size -1 5 4 pop(Q) pop(Q) 2 21 17

36 36 Pop size=5 S1S1 S2S2 pop(Q): if empty?(Q) error if empty?(S 1 ) then move(S 2, S 1 ) pop( S 1 ); size ← size -1 5 pop(Q) pop(Q) 2 21 17 4

37 37 Pop size=5 S1S1 S2S2 pop(Q): if empty?(Q) error if empty?(S 1 ) then move(S 2, S 1 ) pop( S 1 ); size ← size -1 pop(Q) pop(Q) 2 21 17 4 5

38 38 Pop size=4 S1S1 S2S2 pop(Q): if empty?(Q) error if empty?(S 1 ) then move(S 2, S 1 ) pop( S 1 ); size ← size -1 pop(Q) pop(Q) 2 21 17 4

39 39 move(S 2, S 1 ) while not empty?(S 2 ) do x ← pop(S 2 ) push(x,S 1 )

40 40 Analysis O(n) worst case time per operation

41 41 Amortized Analysis How long it takes to perform m operations on the worst case ? O(nm) Is this tight ?

42 42 Key Observation An expensive operation cannot occur too often !

43 43 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: 1.Enters S1 exactly once 2.Moves from S1 to S2 at most once 3.Exits S2 at most once  #ops per element ≤ 3 m operations  #elements ≤ m  work ≤ 3 m S2S2 S1S1 5 4 2 21 7

44 44 The potential formalism The potential is in fact the bank

45 45 Amortized(op) = actual(op) +  Define Define: a potential function 

46 46 Amortized(op 1 ) = actual(op 1 ) +  1 -  0 Amortized(op 2 ) = actual(op 2 ) +  2 -  1 Amortized(op n ) = actual(op n ) +  n -  (n-1) ………… +  i Amortized(op i ) =  i actual(op i ) +  n -  0  i Amortized(op i )   i actual(op i ) if  n -  0  0

47 47 Potential based Proof (on your own) Consider Recall that: Amortized(op) = actual(op) + ΔΦ This is O(1) if a move does not occur Say we move S 2 : Then the actual time is |S 2 | + O(1) ΔΦ = -|S 2 | So the amortized time is O(1) Think of Φ as accumulation of easy operations covering for future potential “damage”

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

49 49 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()

50 50 Implementation with doubly linked lists 5 head size=2 tail 13 x.next x.element x.prev x

51 51 Empty list head size=0 tail We use two sentinels here to make the code simpler

52 52 Push 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 5 head size=1 tail

53 53 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 5 head size=1 tail push(4,D) 4

54 54 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 5 head size=1 tail push(4,D) 4

55 55 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 5 head size=1 tail push(4,D) 4

56 56 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 5 head size=2 tail push(4,D) 4

57 57 Implementations of the other operations are similar Try by yourself

58 58 Back to deques Alternative implementation using stacks

59 59 Implementation with stacks size=5 13 S1S1 S2S2 push(x,D): push(x,S 1 ) 5 4 17 21 push(2,D)

60 60 Implementation with stacks size=6 2 13 S1S1 S2S2 push(x,D): push(x,S 1 ) 5 4 17 21 push(2,D)

61 61 Pop size=6 S1S1 S2S2 pop(D): if empty?(D) error if empty?(S 1 ) then split(S 2, S 1 ) pop( S 1 ) 2 13 5 4 17 21 pop(D)

62 62 Pop size=5 S1S1 S2S2 pop(D): if empty?(D) error if empty?(S 1 ) then split(S 2, S 1 ) pop( S 1 ) 13 5 4 17 21 pop(D) pop(D)

63 63 Pop size=4 S1S1 S2S2 pop(D): if empty?(D) error if empty?(S 1 ) then split(S 2, S 1 ) pop( S 1 ) 5 4 17 21 pop(D) pop(D)

64 64 Pop 5 4 17 21 size=4 S1S1 S2S2 pop(D): if empty?(D) error if empty?(S 1 ) then split(S 2, S 1 ) pop( S 1 ) pop(D)

65 65 Pop 5 4 17 21 size=4 S1S1 S2S2 pop(D): if empty?(D) error if empty?(S 1 ) then split(S 2, S 1 ) pop( S 1 ) pop(D)

66 66 Pop 17 21 size=4 S1S1 S2S2 pop(D): if empty?(D) error if empty?(S 1 ) then split(S 2, S 1 ) pop( S 1 ) pop(D) 5 4

67 67 Pop 17 21 size=4 S1S1 S2S2 pop(D): if empty?(D) error if empty?(S 1 ) then split(S 2, S 1 ) pop( S 1 ) pop(D) 4

68 68 Pop 17 21 size=3 S1S1 S2S2 pop(D): if empty?(D) error if empty?(S 1 ) then split(S 2, S 1 ) pop( S 1 ) pop(D) 4

69 69 Split 5 4 17 21 S1S1 S2S2 S3S3

70 70 Split 5 4 17 S1S1 S2S2 S3S3 21

71 71 Split 5 4 S1S1 S2S2 S3S3 21 17

72 72 Split 5 S1S1 S2S2 S3S3 21 17 4

73 73 Split S1S1 S2S2 S3S3 21 17 54

74 74 Split S1S1 S2S2 S3S3 21 17 54

75 75 Split S1S1 S2S2 S3S3 2117 54

76 76 Split (same thing in reverse) 5 4S1S1 S2S2 S3S3

77 77 split(S 2, S 1 ) S 3 ← make-stack() d ← size(S 2 ) while (i ≤ ⌊ d/2 ⌋ ) do x ← pop(S 2 ) push(x,S 3 ) i ← i+1 while (i ≤ ⌈ d/2 ⌉ ) do x ← pop(S 2 ) push(x,S 1 ) i ← i+1 while (i ≤ ⌊ d/2 ⌋ ) do x ← pop(S 3 ) push(x,S 2 ) i ← i+1

78 78 Analysis O(n) worst case time per operation

79 79 Thm: If we start with an empty deque and perform m operations then it takes O(m) time

80 80 Amortized Analysis How long it takes to perform m operations on the worst case ? O(nm) Really ?

81 81 Key Observation An expensive operation cannot occur too often !

82 82 A better bound Consider This is O(1) if no splitting occurs Say we split S 1 : Then the actual time is |S 1 | + O(1) ΔΦ = -|S 1 | (S 2 empty) So the amortized time is O(1) Recall that: Amortized(op) = actual(op) + ΔΦ Think of Φ as accumulation of easy operations covering for future potential “damage”


Download ppt "1 Abstract Data Types Queue + Dequeue Amortized analysis."

Similar presentations


Ads by Google