📚 L8: Amortized Analysis

Lecture Goal

Understand how to analyze the total cost of a sequence of operations, rather than individual operation costs, using three methods: aggregate, accounting, and potential.

The Big Picture

Some data structures have operations that are usually cheap but occasionally expensive. Worst-case analysis would overestimate the total cost. Amortized analysis gives a more realistic picture by averaging costs over a sequence — showing that occasional expensive operations don’t doom overall performance.


1. What is Amortized Analysis?

🤔 The Core Problem

Some data structures have operations with varying costs:

  • Most operations are cheap
  • Occasionally, an operation is very expensive
  • What’s the true cost over many operations?

💡 The Amortized Concept

Amortized Analysis asks: “What is the average cost per operation over a sequence of operations?”

flowchart LR
    subgraph Operations ["Sequence of n Operations"]
        O1["Op 1<br/>Cost: 1"]
        O2["Op 2<br/>Cost: 1"]
        O3["Op 3<br/>Cost: n"]
        O4["Op 4<br/>Cost: 1"]
        On["..."]
    end

    Total["Total: O(n) operations<br/>Some expensive, most cheap"]

    Amortized["Amortized Cost<br/>= Total/n<br/>= O(1)"]

    Operations --> Total
    Total --> Amortized

    style O3 fill:#ff9999
    style Amortized fill:#c8e6c9

The Detective Analogy 🕵️

Imagine you’re a detective solving cases. Most cases are easy (P problems) — you follow the clues and solve them quickly. But some cases require checking every possible suspect (expensive operations). However, if you solve 100 cases and only 1 was hard, your average case-solving time is still pretty good. That’s amortized analysis!


📖 Key Terminology

TermDefinition
Worst-case analysisConsiders the most expensive single operation
Amortized analysisConsiders average cost per operation over a sequence
Average-case analysisProbabilistic expectation over random inputs
Total costSum of costs over all operations

💡 Warm-Up Example: Dynamic Array

A dynamic array (like Python list or Java ArrayList) doubles in size when full:

flowchart LR
    subgraph Cheap ["Most Insertions: O(1)"]
        C1["Insert<br/>Cost: 1"]
        C2["Insert<br/>Cost: 1"]
    end

    subgraph Expensive ["Occasional: O(n)"]
        E1["Array full!<br/>Double size<br/>Copy all elements"]
    end

    Cheap -->|"n operations"| Expensive

    style Cheap fill:#c8e6c9
    style Expensive fill:#ff9999
  • Worst-case per insertion: (when array doubles)
  • Amortized cost: (expensive operations are rare)

⚠️ Common Pitfalls

Confusing amortized with average-case

Amortized analysis is not probabilistic. It’s a worst-case bound on the average over any sequence of operations. Average-case assumes random inputs; amortized makes no such assumption.

Thinking "worst case × n" is correct

For operations with worst-case each, you might think total is . But the expensive case is rare! The amortized analysis shows total is actually .


❓ Mock Exam Questions

Q1: Amortized vs Worst-Case

If an operation has worst-case cost , what does amortized analysis tell us?

Answer

Answer: Amortized analysis might show average cost per operation is much lower

Because the expensive operation occurs rarely. For dynamic array, worst-case is but amortized is .


2. Aggregate Method

🧠 Core Concept

The Aggregate Method computes the total cost of all operations and divides by .

flowchart TD
    subgraph Method ["Aggregate Method"]
        Step1["1. Compute total cost of n operations"]
        Step2["2. Divide by n"]
        Step3["3. Result: amortized cost per operation"]
    end

    Step1 --> Step2 --> Step3

    style Step1 fill:#e1f5fe
    style Step3 fill:#c8e6c9

Key Idea: No need to track individual costs — just sum everything!


📖 Example 1: Dynamic Array

Starting with an empty array of capacity 1, do insertions:

OperationArray SizeCapacityCostNotes
1111Insert, no resize
2222Copy 1 + insert 1, capacity doubled
3343Copy 2 + insert 1
4441Insert, no resize
5585Copy 4 + insert 1

Analysis:

flowchart LR
    subgraph Costs ["Cost Breakdown"]
        Insert["Insertions: n × 1 = n"]
        Copy["Copies: 1+2+4+... "]
    end

    Total["Total < 3n"]

    Insert --> Total
    Copy --> Total

    style Total fill:#c8e6c9
  • Insertions: operations, each costs 1 → Total:
  • Copying: Occurs at capacities 1, 2, 4, 8, … → Total: where
  • This is a geometric series:

Total cost:

Amortized cost:


📖 Example 2: Binary Counter

A -bit binary counter, incremented times starting from 0.

Key Observation:

BitFlips Every…Total Flips
Bit 0 (LSB)1 increment
Bit 12 increments
Bit 24 increments
Bit increments

Total bit flips:

Amortized cost per increment:


⚠️ Common Pitfalls

Forgetting geometric series formula

Sum of powers of 2 is , not . Remember:

Counting each bit flip equally

Higher-order bits flip exponentially less often! Bit flips every operations, not every operation.


❓ Mock Exam Questions

Q2: Binary Counter Bit Flips

In a binary counter incremented times, how many times does bit 3 flip?

Answer

Answer: times

Bit flips every increments. Bit 3 flips every increments, so it flips times.

Q3: Dynamic Array Copy Cost

After insertions into a dynamic array that doubles when full, what is the total copying cost?

Answer

Answer:

Copies occur at sizes 1, 2, 4, 8, … up to first power of 2 ≥ . Total: .


3. Accounting Method

🧠 Core Concept

The Accounting Method assigns an amortized cost to each operation and uses “credits” to pay for expensive operations.

flowchart TD
    subgraph Cheap ["Cheap Operations"]
        Charge["Charge amortized cost"]
        Save["Save surplus as 'credit'"]
    end

    subgraph Expensive ["Expensive Operations"]
        Use["Use saved credits"]
        Pay["Pay the actual cost"]
    end

    Cheap --> Expensive

    style Cheap fill:#c8e6c9
    style Expensive fill:#fff9c4

Key Idea:

  • Charge each operation an amortized cost (may differ from actual cost)
  • Store surplus as credit for future expensive operations
  • Credit must never go negative!

The Savings Account Analogy 💰

Think of it like a savings account. You deposit money during good times (cheap operations), and withdraw during expensive times (expensive operations). The goal is to always have enough saved up — credit never goes negative!


📖 Example 1: Dynamic Array

Strategy: Charge amortized cost of 3 for each insertion.

OperationActual CostAmortized CostCredit
Insert (no resize)13+2
Insert (with resize)3varies

Why does this work?

When array is full and needs expansion from size to :

  • We need to copy elements → cost =
  • We have saved credits from previous insertions (2 credits per element)
  • Credits saved ≥ copy cost ✅
flowchart LR
    subgraph Saving ["Each Insertion"]
        Charge["Charge: 3"]
        Use1["Use: 1 (for insert)"]
        Save["Save: 2 (credit)"]
    end

    subgraph Resize ["When Array Full"]
        Need["Need: k (to copy)"]
        Have["Have: 2k credits"]
    end

    Saving --> Resize

    style Saving fill:#c8e6c9
    style Resize fill:#fff9c4

Result: Total amortized cost = for operations → per operation ✅


📖 Example 2: Binary Counter

Strategy: Charge amortized cost of 2 for each increment.

WhatCostCredit
Set bit 0→11+1 (from the 2 charged)
Reset bit 1→01Use saved credit

Accounting:

  • When bit flips 0→1: costs 1, charge 2, save 1 credit
  • When bit flips 1→0: costs 1, use the saved credit from when it was set
  • Every 1→0 flip is “prepaid” by a previous 0→1 flip
flowchart LR
    subgraph Bits ["Bit Life Cycle"]
        Zero["Bit = 0"]
        One["Bit = 1"]
        Back["Bit = 0"]
    end

    Zero -->|"Set: cost 1, charge 2, save 1"| One
    One -->|"Reset: cost 1, use saved credit"| Back

    style Zero fill:#e1f5fe
    style One fill:#c8e6c9

Result: Amortized cost per increment ≤ 2 →


⚠️ Common Pitfalls

Letting credit go negative

You must prove credit at all times. If credit ever goes negative, your amortized bound is wrong.

Not accounting for all costs

Every actual cost must be paid — either by the amortized charge or by credits. Don’t forget any operations.


❓ Mock Exam Questions

Q4: Accounting Method Credit

For dynamic array with amortized cost 3, how much credit is saved per non-resize insertion?

Answer

Answer: 2 credits

Charge 3, actual cost is 1, so save 2 credits for future resize.


4. Potential Method

🧠 Core Concept

The Potential Method uses a mathematical potential function on the data structure state.

Where:

  • = amortized cost of operation
  • = actual cost of operation
  • = potential after operation
flowchart TD
    subgraph Formula ["Potential Method Formula"]
        AC["Amortized Cost"]
        Actual["Actual Cost c_i"]
        Delta["Potential Change<br/>Φ(D_i) - Φ(D_{i-1})"]
    end

    AC -->|"="| Actual
    AC -->|"+"| Delta

    style AC fill:#c8e6c9
    style Actual fill:#e1f5fe
    style Delta fill:#fff9c4

Requirements:

  • (initial potential is zero)
  • for all (potential never negative)

The Physics Analogy ⚡

Think of potential energy. A ball at the top of a hill has high potential energy — it can “pay” for the descent later. Similarly, the potential function stores “energy” in the data structure for future expensive operations!


📖 Example 1: Dynamic Array

Potential Function:

Case 1: Insert without resize

QuantityBeforeAfter
Size
Capacity
Potential
  • Actual cost: 1
  • Potential change:
  • Amortized cost:

Case 2: Insert with resize (array full)

QuantityBeforeAfter
Size
Capacity
Potential
  • Actual cost: (copy) + (insert) =
  • Potential change:
  • Amortized cost:

📖 Example 2: Binary Counter

Potential Function:

Analysis:

When we increment and flip bits:

  • Suppose we flip trailing 1s to 0, and one 0 to 1
  • Actual cost: bit flips
  • Potential change: lose ones, gain 1 one → change =
  • Amortized cost:
flowchart LR
    subgraph Increment ["Increment Operation"]
        Before["Before: ...0111"]
        After["After: ...1000"]
    end

    subgraph Analysis ["Analysis"]
        Flips["Flip t 1s to 0<br/>Flip one 0 to 1"]
        Potential["Potential: -t + 1"]
        Amortized["Amortized: t+1 + (-t+1) = 2"]
    end

    Increment --> Analysis

    style Amortized fill:#c8e6c9

⚠️ Common Pitfalls

Choosing a potential that goes negative

You must prove for all states. If potential ever goes negative, the bound is invalid.

Forgetting the initial condition

must hold for the initial state. This ensures the total amortized cost bounds the total actual cost.


❓ Mock Exam Questions

Q5: Potential Method Formula

In the potential method, what is the formula for amortized cost?

Answer

Answer:

Amortized cost = actual cost + potential change.

Q6: Potential Change Interpretation

If actual cost is 10 and potential decreases by 3, what is the amortized cost?

Answer

Answer:

Amortized cost = . When potential decreases, we “spend” saved energy, reducing the amortized cost.


5. Comparison of Methods

🧠 Core Concept

MethodApproachBest For
AggregateSum all costs, divide by Simple sequences with predictable patterns
AccountingAssign amortized costs, track creditIntuitive understanding, teaching
PotentialMathematical potential functionRigorous proofs, complex data structures
flowchart TD
    subgraph Methods ["Three Methods"]
        Agg["Aggregate Method<br/>Sum and divide"]
        Acc["Accounting Method<br/>Credits and charges"]
        Pot["Potential Method<br/>Mathematical function"]
    end

    Result["All give same<br/>asymptotic bound"]

    Agg --> Result
    Acc --> Result
    Pot --> Result

    style Result fill:#c8e6c9

📖 When to Use Each Method

ScenarioRecommended MethodWhy
Simple, uniform operationsAggregateEasy to calculate total
Need intuitive explanationAccountingCredit concept is easy to explain
Complex data structuresPotentialMathematical rigor
Proving bounds for publicationsPotentialMost rigorous method
Teaching amortized analysisAccountingMost intuitive

The Budgeting Analogy 📊

  • Aggregate is like calculating your total yearly expenses and dividing by 12 to get monthly average
  • Accounting is like budgeting with envelopes — setting aside money each month for known future expenses
  • Potential is like physics equations — tracking energy levels precisely

⚠️ Common Pitfalls

Using the wrong method for the problem

Some problems are easier with one method. Practice all three to know which to use.

Inconsistent bounds between methods

All three methods should give the same asymptotic bound. If not, check your analysis.


6. Classic Examples Summary

📊 Dynamic Array (Resizable Array)

MethodAnalysisResult
AggregateTotal =
AccountingCharge 3, save 2 for resize
Potential

📊 Binary Counter

MethodAnalysisResult
AggregateTotal flips <
AccountingCharge 2, save 1 per 1-bit
Potential = number of 1-bits

🔗 Connections

📚 Lecture🔗 Connection
L9Amortized analysis used in analyzing complex data structures

The Key Insight

Amortized analysis reveals that occasional expensive operations don’t doom overall performance. By averaging over a sequence, we see the true cost — like understanding that a gym membership’s value comes from consistent use, not just one intense session! 🏋️


7. Mock Exam Questions

📝 Multiple Choice

Q1: Amortized vs Worst-Case

A dynamic array has worst-case insertion cost . What is the amortized insertion cost?

Answer

Answer: (b)

Even though some insertions cost when the array resizes, the amortized cost over operations is because resizing happens rarely (logarithmically many times).

Q2: Aggregate Method

In the aggregate method, how do we compute amortized cost?

Answer

Answer: (b) Sum total cost and divide by

The aggregate method computes the total cost of all operations and divides by to get average cost per operation.

Q3: Binary Counter

A binary counter incremented times has how many total bit flips?

Answer

Answer: (b)

Bit flips times. Total: .


✍️ Open-Ended Practice Problems

P1: Stack with Multipop

A stack supports push (cost 1) and multipop() (cost where is stack size). Using any method, show that a sequence of operations has amortized cost per operation.

Answer

Solution (Accounting Method):

  • Charge amortized cost 2 for push, 0 for multipop
  • Each push saves 1 credit on the element
  • Each pop uses 1 credit from the element
  • Total pushes , so total credits total pops
  • Credit never goes negative
  • Amortized cost:
  • Per operation:

Solution (Potential Method):

Define size of stack

  • Push: cost 1, , amortized =
  • Multipop(): cost , , amortized =

Both operations have constant amortized cost ✅

P2: Potential Method for Dynamic Array

(a) Define a potential function for a dynamic array and prove that insert without resize has amortized cost .

(b) Using the same potential function, prove that insert with resize also has amortized cost .

Answer

Potential Function:

Initial state: (empty array) ✅

Non-negative: Since size capacity,

(a) Insert without resize:

  • Actual cost: 1
  • Size increases by 1, capacity unchanged
  • Amortized cost:

(b) Insert with resize (array was full):

  • Before: size = , capacity =
  • After: size = , capacity =
  • Actual cost: (copy) + (insert) =
  • Amortized cost:

P3: Comparing Methods

Explain why all three methods (aggregate, accounting, potential) give the same asymptotic bound for the dynamic array.

Answer

All three methods bound the same quantity: total actual cost.

  • Aggregate: Directly counts total cost <
  • Accounting: Total amortized cost = , and credit means total actual total amortized
  • Potential: Total amortized = Total actual + , and means total actual total amortized

All methods show total cost = , so per-operation = .