Download - Abstract Data Types Stack, Queue Amortized analysis

Transcript
Page 1: Abstract Data Types Stack, Queue Amortized analysis

1

Abstract Data TypesStack, Queue

Amortized analysis

Page 2: Abstract Data Types Stack, Queue Amortized analysis

2

ADT is an interface

• It defines– the type of the data stored– operations, what each operation does

(not how)– parameters of each operation

Page 3: Abstract Data Types Stack, Queue Amortized analysis

3

ADT

Application

Implementation of theData structure

חוזה בין מתכנת האפליקציה

ומיישם מבנה הנתונים

ממשק

Page 4: Abstract Data Types Stack, Queue Amortized analysis

4

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

Page 5: Abstract Data Types Stack, Queue Amortized analysis

5

The Stack Data Abstraction

push

push

push

Page 6: Abstract Data Types Stack, Queue Amortized analysis

6

The Stack Data Abstraction

push

push

push

pop

push

Last in,First out.

Page 7: Abstract Data Types Stack, Queue Amortized analysis

7

• Evaluate an expression in postfix or Reverse Polish Notation

Infix Postfix

(2+ 3) * 5 2 3 + 5 *

( (5 * (7 / 3) ) – (2 * 7) ) 5 7 3 / * 2 7 *-

A stack application

Page 8: Abstract Data Types Stack, Queue Amortized analysis

8

2 3 + 5 *

A stack application

23

Page 9: Abstract Data Types Stack, Queue Amortized analysis

9

2 3 + 5 *

A stack application

55

Page 10: Abstract Data Types Stack, Queue Amortized analysis

10

2 3 + 5 *

A stack application

25

Page 11: Abstract Data Types Stack, Queue Amortized analysis

11

S ← make-stack()while ( not eof ) do B ← read the next data;

if B is an operand then push(B,S) else X ← pop(S)

Y ← pop(S) Z ← Apply the operation B on X and Y push(Z,S)return(top(S))

Pseudo-code

Page 12: Abstract Data Types Stack, Queue Amortized analysis

12

Implementation

• We will be interested in algorithms to implement the ADT..

• And their efficiency..

Page 13: Abstract Data Types Stack, Queue Amortized analysis

13

Using an array

12 1 3A

A[0] A[1]

t

The stack is represented by the array A and variable t

A[2] A[N-1]

1213

Page 14: Abstract Data Types Stack, Queue Amortized analysis

14

Using an array

12 1 3A

A[0] A[1]

t

make-stack(): Allocates the array A, which is of some fixed size N, sets t ← -1

The stack is represented by the array A and variable t

A[2] A[N-1]

Page 15: Abstract Data Types Stack, Queue Amortized analysis

15

Operations

12 1 3A

t

size(S): return (t+1)

empty?(S): return (t < 0)

top(S): if empty?(S) then error else return A[t]

A[N-1]A[0] A[1]

A[2]

Page 16: Abstract Data Types Stack, Queue Amortized analysis

16

Pop

12 1 3A

t

pop(S): if empty?(S) then error else e ←A[t] t ← t – 1 return (e)

A[N-1]A[0] A[1]

A[2]

pop(S)

Page 17: Abstract Data Types Stack, Queue Amortized analysis

17

Pop

12 1 3A

t

A[N-1]A[0] A[1]

A[2]

pop(S): if empty?(S) then error else e ←A[t] t ← t – 1 return (e)

pop(S)

Page 18: Abstract Data Types Stack, Queue Amortized analysis

18

Push

12 1 3A

t

push(x,S): if size(S) = N then error else t ←t+1 A[t] ← x

A[N-1]A[0] A[1]

A[2]

push(5,S)

Page 19: Abstract Data Types Stack, Queue Amortized analysis

19

Push

12 1 5A

t

push(x,S): if size(S) = N then error else t ←t+1 A[t] ← x

A[N-1]A[0] A[1]

A[2]

push(5,S)

Page 20: Abstract Data Types Stack, Queue Amortized analysis

20

Implementation with lists

12 1 5

top

size=3

x.element

x.nextx

Page 21: Abstract Data Types Stack, Queue Amortized analysis

21

Implementation with lists

12 1 5

top

make-stack(): top ← null size ← 0

size=3

Page 22: Abstract Data Types Stack, Queue Amortized analysis

22

Operations

12 1 5

top

size(S): return (size)

empty?(S): return (top = null)

top(S): if empty?(S) then error else return top.element

size=3

Page 23: Abstract Data Types Stack, Queue Amortized analysis

23

Pop

12 1 5

top

pop(S): if empty?(S) then error else e ←top.element top ← top.next size ← size-1 return (e)

pop(S)

size=3

Page 24: Abstract Data Types Stack, Queue Amortized analysis

24

Pop

12 1 5

top

pop(S): if empty?(S) then error else e ←top.element top ← top.next size ← size-1 return (e)

pop(S)

size=2

Page 25: Abstract Data Types Stack, Queue Amortized analysis

25

Garbage collection

1 5

top

pop(S): if empty?(S) then error else e ←top.element top ← top.next size ← size-1 return (e)

pop(S)

size=2

Page 26: Abstract Data Types Stack, Queue Amortized analysis

26

Push

1 5

topsize=2

push(x,S): n = new node n.element ←x n.next ← top top ← n size ← size + 1 push(5,S)

Page 27: Abstract Data Types Stack, Queue Amortized analysis

27

Push

1 5

topsize=2

push(x,S): n = new node n.element ←x n.next ← top top ← n size ← size + 1 push(5,S)

5

Page 28: Abstract Data Types Stack, Queue Amortized analysis

28

Push

1 5

topsize=2

push(x,S): n = new node n.element ←x n.next ← top top ← n size ← size + 1 push(5,S)

5

Page 29: Abstract Data Types Stack, Queue Amortized analysis

29

Push

1 5

topsize=3

push(x,S): n = new node n.element ←x n.next ← top top ← n size ← size + 1 push(5,S)

5

Page 30: Abstract Data Types Stack, Queue Amortized analysis

30

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

Page 31: Abstract Data Types Stack, Queue Amortized analysis

31

Big-O

) ו- כך ש:c - קיים ) ( ( ))T n O f n0n

0)()( nnnfcnT

דוגמא:2

( ) ( 1)T n n

)(4)1(222nOnn

Page 32: Abstract Data Types Stack, Queue Amortized analysis

32

Big-O

))(()( ngOnf

cg(n)

f(n)

n0

Page 33: Abstract Data Types Stack, Queue Amortized analysis

33

• 4n O(n2)

• 4n2 O(n2)

• 2n O(n10)

• 10 O(1)

• 100n3+10n O(n3)

• log2(n) O(log10(n))

More examples

Page 34: Abstract Data Types Stack, Queue Amortized analysis

34

The running time of our stack and queue operations

• Each operation takes O(1) time

Page 35: Abstract Data Types Stack, Queue Amortized analysis

35

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

Page 36: Abstract Data Types Stack, Queue Amortized analysis

36

Push

push(x,S): if size(S) = N then allocate a new array of size 2N copy the old array to the new one t ←t+1 A[t] ← x

12 1A

t

A[N-1]A[0] A[1]

Page 37: Abstract Data Types Stack, Queue Amortized analysis

37

Push

push(x,S): if size(S) = N then allocate a new array of size 2N copy the old array to the new one t ←t+1 A[t] ← x

12 1 3 3A 4 5 7 3 2 8 1

A[N-1]A[0] A[1]

t

push(5,S)

Page 38: Abstract Data Types Stack, Queue Amortized analysis

38

Push

push(x,S): if size(S) = N then allocate a new array of size 2N copy the old array to the new one t ←t+1 A[t] ← x

push(5,S)

12 1 3 3A 4 5 7 3 2 8 1

A[0] A[1]

t

Page 39: Abstract Data Types Stack, Queue Amortized analysis

39

Push

push(x,S): if size(S) = N then allocate a new array of size 2N copy the old array to the new one t ←t+1 A[t] ← x push(5,S)

12 1 3 3A 4 5 7 3 2 8 1

A[0] A[1]

12 1 3 3 4 5 7 3 2 8 1

t

Page 40: Abstract Data Types Stack, Queue Amortized analysis

40

Push

push(x,S): if size(S) = N then allocate a new array of size 2N copy the old array to the new one t ←t+1 A[t] ← x

t

A[2N-1]

12 1 3 3A 4 5 7 3 2 8 1

A[0] A[1]

push(5,S)

Page 41: Abstract Data Types Stack, Queue Amortized analysis

41

Push

push(x,S): if size(S) = N then allocate a new array of size 2N copy the old array to the new one t ←t+1 A[t] ← x

5

A[2N-1]

12 1 3 3A 4 5 7 3 2 8 1

A[0] A[1]

t

push(5,S)

Page 42: Abstract Data Types Stack, Queue Amortized analysis

42

Analysis

• An operation may take O(n) worst case time !

• But that cannot happen often..

Page 43: Abstract Data Types Stack, Queue Amortized analysis

43

Amortized Analysis

• How long it takes to do m operations ?

• Well, O(nm)

• Yes, but can it really take that long ?

Page 44: Abstract Data Types Stack, Queue Amortized analysis

44

Page 45: Abstract Data Types Stack, Queue Amortized analysis

45

x

Page 46: Abstract Data Types Stack, Queue Amortized analysis

46

x x

Page 47: Abstract Data Types Stack, Queue Amortized analysis

47

x x

x x x

Page 48: Abstract Data Types Stack, Queue Amortized analysis

48

x x

x x x x

Page 49: Abstract Data Types Stack, Queue Amortized analysis

49

x x

x x x x

x x x x x

Page 50: Abstract Data Types Stack, Queue Amortized analysis

50

x x

x x x x

x x x x x x

Page 51: Abstract Data Types Stack, Queue Amortized analysis

51

x x

x x x x

x x x x x x x

Page 52: Abstract Data Types Stack, Queue Amortized analysis

52

x x

x x x x

x x x x x x x x

Page 53: Abstract Data Types Stack, Queue Amortized analysis

53

x x

x x x x

x x x x x x x x

x x x x x x x x x

Page 54: Abstract Data Types Stack, Queue Amortized analysis

54

x x

x x x x

x x x x x x x x

x x x x x x x x x x

Page 55: Abstract Data Types Stack, Queue Amortized analysis

55

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

Page 56: Abstract Data Types Stack, Queue Amortized analysis

56

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

Only after z-1 pushes that cost 1 we will have a push that costs 2z+1

Let z be the size of the array we just copied

Page 57: Abstract Data Types Stack, Queue Amortized analysis

57

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

3+(2∙4+1)=3∙4

7+(2∙8+1)= 3∙8

Total cost O(m) !!

Start from the second row: z=2

1+(2∙2+1)=3∙2

z=4 z=8

Page 58: Abstract Data Types Stack, Queue Amortized analysis

58

Theorem: A sequence of m operations on a stack takes O(m) time

proof.

Page 59: Abstract Data Types Stack, Queue Amortized analysis

59

Amortized Analysis (The bank’s view)

• We will have a bank

• An operation can either pay a token for a unit of work by itself, or take a token from the bank to pay for it

• An operation can put tokens in the bank

• If the bank never has a negative balance then the total # of tokens spent by the operations bounds the total work

Page 60: Abstract Data Types Stack, Queue Amortized analysis

60

For a proof:

• Define exactly how each operation pays for its work, and how many tokens it puts in the bank

• Prove that the balance in the bank is always non-negative

• Count the total # of tokens – that’s your bound

Page 61: Abstract Data Types Stack, Queue Amortized analysis

61

“Easy” push

• when we push an item, we also put ≤ two tokens, one on the item which we insert, and one on another item if there is some item without a token

A[N-1]

12 1 3 3A 4 5 7 3 2 8 1

A[0] A[1]

t

Page 62: Abstract Data Types Stack, Queue Amortized analysis

62

5

A[N-1]

12 1 3 3A 4 5 7 3 2 8 1

A[0] A[1]

t

“Easy” push

• when we push an item, we also put ≤ two tokens, one on the item which we insert, and one on another item if there is some item without a token

Page 63: Abstract Data Types Stack, Queue Amortized analysis

63

5 6

A[N-1]

12 1 3 3A 4 5 7 3 2 8 1

A[0] A[1]

t

Page 64: Abstract Data Types Stack, Queue Amortized analysis

64

5 6 6 7 1 10 4 67 2 5 7

A[N-1]

12 1 3 3A 4 5 7 3 2 8 1

A[0] A[1]

t

Page 65: Abstract Data Types Stack, Queue Amortized analysis

65

“hard” push

• Tokens from the bank “pay” for copying the array into the larger array

5 6 6 7 1 10 4 67 2 5 7

A[N-1]

12 1 3 3A 4 5 7 3 2 8 1

A[0] A[1]

t

Page 66: Abstract Data Types Stack, Queue Amortized analysis

66

• Then you pay a token and put two in the bank as an “easy” push

5 6 6 7 1 10 4 67 2 5 712 1 3 3 4 5 7 3 2 8 1 A

t

5 6 6 7 1 10 4 67 2 5 712 1 3 3 4 5 7 3 2 8 1 4

t

“hard” push

Page 67: Abstract Data Types Stack, Queue Amortized analysis

67

Need to prove

• The balance is never negative:

• When we get to an expensive push there are enough tokens to pay for copying

• By induction: prove that after the i-th push following a copying there are 2i tokens in the bank

Page 68: Abstract Data Types Stack, Queue Amortized analysis

68

How many tokens we spent ?

• Each operation spent 3 tokens

Page 69: Abstract Data Types Stack, Queue Amortized analysis

69

Summary

• So the total # of tokens is 3mTHM: A sequence of m operations takes

O(m) time !! (we finished the proof)

• Each operation takes O(1) amortized time

Page 70: Abstract Data Types Stack, Queue Amortized analysis

70

Theorem: A sequence of m operations on a stack takes O(m) time

proof (2) .

• We formalize the bank as a potential function

Page 71: Abstract Data Types Stack, Queue Amortized analysis

71

Amortized(op) = actual(op) +

Define

Define: a potential function

Page 72: Abstract Data Types Stack, Queue Amortized analysis

72

Amortized(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

Page 73: Abstract Data Types Stack, Queue Amortized analysis

73

Example: Our extendable arrays

Define a potential of the stack

2( 1) 2( 1) 0( )

0

t N if t NS

Otherwise

Page 74: Abstract Data Types Stack, Queue Amortized analysis

74

Amortized(push) = actual(push) + =

1 + 2(t+2) – N - (2(t+1) – N) = 3

Amortized(push) = N + 1 + =

N + 1 + (2 - N) = 3

Amortized(pop) = 1 + =

1 + 2(t-1) – N - (2t – N) = -1

With copying:

Without copying:

Page 75: Abstract Data Types Stack, Queue Amortized analysis

75

Amortized(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 03m ≥

Page 76: Abstract Data Types Stack, Queue Amortized analysis

76

Summary

• So the total # of tokens is 3m THM: A sequence of m operations

starting from an empty stack takes O(m) time !!

• Each operations take O(1) amortized time

Page 77: Abstract Data Types Stack, Queue Amortized analysis

77

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

Page 78: Abstract Data Types Stack, Queue Amortized analysis

78

The Queue Data Abstraction

inject

inject

Page 79: Abstract Data Types Stack, Queue Amortized analysis

79

The Queue Data Abstraction

inject

inject

inject

inject

popFirst in,First out (FIFO).

Page 80: Abstract Data Types Stack, Queue Amortized analysis

80

Using an array

12 1 4 2A 5

A[0] A[1]

t

pop(Q)

A[2] A[N-1]

Page 81: Abstract Data Types Stack, Queue Amortized analysis

81

Using an array

1 4 2 5A

A[0] A[1]

t

pop(Q)

A[2] A[N-1]

Page 82: Abstract Data Types Stack, Queue Amortized analysis

82

Using an array

1 4 2 5A

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

Page 83: Abstract Data Types Stack, Queue Amortized analysis

83

Using an array

12 1 4 2A 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

Page 84: Abstract Data Types Stack, Queue Amortized analysis

84

Using an array

12 1 4 2A 5

A[0] A[1]

r

pop(Q)

A[2] A[N-1]

f

Page 85: Abstract Data Types Stack, Queue Amortized analysis

85

Using an array

1 4 2A 5

A[0] A[1]

A[2] A[N-1]

f r

pop(Q)inject(5,Q)

Page 86: Abstract Data Types Stack, Queue Amortized analysis

86

Using an array

1 4 2A 5 5

A[0] A[1]

A[2] A[N-1]

f r

pop(Q)inject(5,Q)inject(5,Q)

Page 87: Abstract Data Types Stack, Queue Amortized analysis

87

Using an array

1 4 2A 5 5 5

A[0] A[1]

A[2] A[N-1]

f r

pop(Q)inject(5,Q)inject(5,Q)pop(Q)pop(Q)

Page 88: Abstract Data Types Stack, Queue Amortized analysis

88

Using an array

2A 5 5 5

A[0] A[1]

A[2] A[N-1]

f r

pop(Q)inject(5,Q)inject(5,Q)pop(Q)pop(Q)pop(Q), inject(5,Q), pop(Q), inject(5,Q),……….

Page 89: Abstract Data Types Stack, Queue Amortized analysis

89

Using an array

A 5 5 5 5

A[0] A[1]

r

A[2] A[N-1]

f

pop(Q)inject(5,Q)inject(5,Q)pop(Q)pop(Q)pop(Q), inject(5,Q), pop(Q), inject(5,Q),……….

Page 90: Abstract Data Types Stack, Queue Amortized analysis

90

Make the array “circular”

5 5 A 5 5

A[0] A[1]

r

A[2] A[N-1]

f

Pop(Q), inject(5,Q), pop(Q), inject(5,Q),……….

Page 91: Abstract Data Types Stack, Queue Amortized analysis

91

Operations

empty?(Q): return (f = r)

top(Q): if empty?(Q) then error else return A[f]

1 4 2A 5

A[0] A[1]

A[2] A[N-1]

f r

Page 92: Abstract Data Types Stack, Queue Amortized analysis

92

Operations

size(Q): if (r >= f) then return (r-f) else return N-(f-r)

1 4 2A 5

A[0] A[1]

A[2] A[N-1]

f r

Page 93: Abstract Data Types Stack, Queue Amortized analysis

93

Operations

size(Q): if (r >= f) then return (r-f) else return N-(f-r)

5 5 A 5 5

A[0] A[1]

r

A[2] A[N-1]

f

Page 94: Abstract Data Types Stack, Queue Amortized analysis

94

Pop

pop(Q)

1 4 2A 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)

Page 95: Abstract Data Types Stack, Queue Amortized analysis

95

Pop

pop(Q): if empty?(Q) then error else e ←A[f] f ← (f + 1) mod N return (e)

pop(Q)

1 4 2A 5

A[0] A[1]

A[2]

f r

Page 96: Abstract Data Types Stack, Queue Amortized analysis

96

Inject

inject(x,Q): if size(Q) = N-1 then error else A[r] ← x r ← (r+1) mod N

inject(5,Q)

4 2A 5

A[0] A[1]

A[2]

f r

Page 97: Abstract Data Types Stack, Queue Amortized analysis

97

Inject

inject(x,Q): if size(Q) = N-1 then error else A[r] ← x r ← (r+1) mod N

inject(5,Q)

4 2A 5 5

A[0] A[1]

A[2]

f r

Page 98: Abstract Data Types Stack, Queue Amortized analysis

98

Implementation with lists

12 1 5

headsize=3

tail

inject(4,Q)

Page 99: Abstract Data Types Stack, Queue Amortized analysis

99

Implementation with lists

12 1 5

headsize=3

tail

inject(4,Q)

4

Page 100: Abstract Data Types Stack, Queue Amortized analysis

100

Implementation with lists

12 1 5

headsize=3

tail

inject(4,Q)

4

Complete the details by yourself

Page 101: Abstract Data Types Stack, Queue Amortized analysis

101

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

Page 102: Abstract Data Types Stack, Queue Amortized analysis

102

Implementation with doubly linked lists

5

head

size=2

tail

13

x.next

x.element

x.prev

x

Page 103: Abstract Data Types Stack, Queue Amortized analysis

103

Empty list

head

size=0

tail

We use two sentinels here to make the code simpler

Page 104: Abstract Data Types Stack, Queue Amortized analysis

104

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

Page 105: Abstract Data Types Stack, Queue Amortized analysis

105

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

Page 106: Abstract Data Types Stack, Queue Amortized analysis

106

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

Page 107: Abstract Data Types Stack, Queue Amortized analysis

107

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

Page 108: Abstract Data Types Stack, Queue Amortized analysis

108

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

Page 109: Abstract Data Types Stack, Queue Amortized analysis

109

Implementations of the other operations are similar

• Try by yourself