Back to Streaming Sketching

Misra-Gries & Space-Saving Invariants

September 28, 2026 Wasil Zafar 21 min read

Prove deterministic frequent-item guarantees.

Table of Contents

  1. Counters That Refuse to Forget the Heavy Keys
  2. The Misra-Gries Cancellation Invariant
  3. Space-Saving Replacement and Error Certificates
  4. Tracking Hot Keys with Bounded Tables
  5. Trace and Extend Frequent-Item Counters

Counters That Refuse to Forget the Heavy Keys

Imagine a small noticeboard at a busy help desk. It has room for only three issue labels, but thousands of requests arrive. A label that keeps reappearing should survive, while one-off issues should cancel one another or be replaced. Misra–Gries and Space-Saving turn this intuition into deterministic streaming algorithms: no random hash event is needed for their core guarantees.

Both algorithms maintain a bounded table of key–counter pairs for an insertion-only stream. When an observed key is already present, its counter rises. Their behavior diverges when an untracked key arrives and the table is full. Misra–Gries (MG) decrements every stored counter and discards zeros; this is counter cancellation. Space-Saving (SS) replaces a minimum-count entry with the new key, assigns the new estimate one more than that minimum, and records the old minimum as an error certificate.

For a tiny MG trace with two counters and stream \(A,B,C,A,A\): after \(A,B\), both counters equal one. The unseen \(C\) meets a full table, so the conceptual group \(A,B,C\) is cancelled and the table empties. The final two \(A\)'s leave \(A:2\). Its exact frequency is three, and the missing one is explained by the single cancellation round. With two SS counters, the arrival of \(C\) instead replaces one minimum entry of estimate one; the new \(C\) entry receives estimate two and error one. It admits that up to one earlier occurrence may be falsely attributed to \(C\).

This deep dive builds on heavy hitters by proving why a bounded candidate table cannot lose a sufficiently frequent key. A residual stream is what remains after deleting conceptual groups of distinct items represented by MG cancellations. A candidate bound states how many keys can be retained and which true heavy keys must be among them. MG counters are lower estimates; SS counters are upper estimates for tracked keys. Neither table alone proves that every retained candidate is truly heavy—an exact second pass or separate verification sketch may still be required.

The stream model matters. The standard invariants here assume unit, positive arrivals. Arbitrary deletions break the cancellation and replacement proofs. Weighted positive updates require a carefully specified weighted variant, not a loop-free reuse of the unit-update pseudocode. Counter overflow, inconsistent key identity, and incorrect tie handling can also invalidate an otherwise deterministic theorem.

A bounded noticeboard becomes two frequent-item algorithms A full candidate board either cancels all labels in Misra-Gries or replaces the smallest label with an error certificate in Space-Saving. Three-slot boardA: 4B: 2C: 1new key D arrives Misra–Griescancel A, B, C, DA:3, B:1, C removedone cancellation roundstored count ≤ truthD not inserted now Space-Savingreplace minimum C:1D:2 with error 1mass remains representedestimate ≥ truthcertificate gives lower bound cancellationreplacementfull-table boundary
ConceptIntuitive meaningExact exampleNon-example or boundaryMain assumptionQuestion answered
Counter cancellationRemove one vote from each candidate and the unseen arrivalWith \(k=2\), \(A,B,C\) cancel togetherDecrementing only the smallest counterUnit positive arrivalsHow can many light keys eliminate one another?
Residual streamItems left after conceptual cancellation groups are removedOne \(A\) remains after deleting \(A,B,C\)The original stream reordered arbitrarily for implementationEach group contains \(k+1\) distinct itemsWhat do MG counters exactly summarize?
Candidate boundA threshold above which a key cannot disappear\(f_i>n/(k+1)\) must remain with \(k\) MG countersEvery retained key is heavyInsertion-only stream and exact decrementsWhich true heavy keys are guaranteed candidates?
MG stored countLower estimate of a tracked keyStored \(2\), exact \(3\), one cancellationAn upper-bound estimateStandard MG update ruleHow much frequency survived cancellation?
SS replacementGive a minimum slot to the new keyReplace count \(4\) by estimate \(5\)Reset new key to one with no certificateUnit positive arrivalsHow does SS keep observing new contenders?
Error certificateMaximum inherited overcount for a tracked SS keyEstimate \(9\), error \(4\), so lower bound \(5\)A probabilistic confidence intervalCorrect minimum at replacementWhat deterministic interval contains its frequency?
Verification passCount only candidates exactly on a replayRecount 20 candidates from stored dataTrusting every candidate as a heavy hitterStream can be replayed or separately auditedWhich candidates truly cross the threshold?
Warm-up

Counters That Refuse to Forget the Heavy Keys

Trace MG with \(k=2\) counters on \(A,B,C,A,A,B,D,A\).

  1. After \(A,B\), the table is \(\{A:1,B:1\}\).
  2. \(C\) is unseen and the table is full, so decrement both to zero and discard them. Record cancellation count \(D=1\).
  3. Process \(A,A,B,D\): just before the last \(A\), the table is full with two of these candidates; apply the rule exactly rather than guessing which labels “look heavy.”
  4. Expected final table is \(\{A:2\}\), while the exact frequencies are \(A:4,B:2,C:1,D:1\).
  5. Check \(0\le f_A-c_A=2\le D=2\), because a second full-table cancellation occurs when \(D\) arrives.

Reflection: why can \(B\), with frequency two, disappear even though \(A\) must survive? Compare both frequencies with \(n/(k+1)=8/3\).

The Misra-Gries Cancellation Invariant

Fix the convention: MG stores at most \(k\) key–counter pairs and processes unit positive arrivals. For item \(x\):

  1. If \(x\) is tracked, increment its counter.
  2. Else, if fewer than \(k\) keys are tracked, insert \(x\) with count one.
  3. Else decrement every stored counter by one and remove zeros; do not insert \(x\) during that update.

Every execution of step 3 can be interpreted as deleting \(k+1\) distinct stream occurrences: the new untracked \(x\), plus one occurrence attributed to each of the \(k\) tracked keys. Let \(D\) be the number of such cancellation rounds. These groups are disjoint, so \[ (k+1)D\le n,\qquad D\le\left\lfloor\frac{n}{k+1}\right\rfloor. \]

After deleting all conceptual groups, the residual multiplicity of every retained item equals its stored counter. For any item \(i\), tracked or not, define \(c_i=0\) when absent. Each cancellation can remove at most one occurrence of \(i\), hence \[ 0\le f_i-c_i\le D\le\left\lfloor\frac{n}{k+1}\right\rfloor. \] This is the central invariant. It immediately proves the candidate theorem: if \(f_i>n/(k+1)\), then \(c_i>0\), so \(i\) must be in the final table. It also gives a deterministic frequency interval \(c_i\le f_i\le c_i+D\). A second pass over only the candidates removes false positives.

The strict inequality matters. At exactly \(n/(k+1)\), an item may vanish. For \(k=2\), stream \(A,B,C\) has every frequency equal to one and \(n/(k+1)=1\); the single cancellation empties the table. Another convention uses \(k-1\) counters and states the threshold as \(n/k\). Both are correct, but mixing the symbol conventions creates an off-by-one theorem.

The proof is order-independent in its guarantee even though the final candidate set and counters can depend on order. It is deterministic: no independence or probability assumption exists. But it is not a general-turnstile proof; a negative update cannot be placed into a \(k+1\)-distinct positive cancellation group. Compared with exact counting, MG trades exact identities below the threshold for \(O(k)\) memory.

Misra-Gries & Space-Saving Invariants: The Misra-Gries Cancellation Invariant
flowchart TD
    A[Insertion-only unit stream] --> B[At most k tracked keys]
    B --> C{Incoming key tracked or free slot?}
    C -->|yes| D[Increment or insert]
    C -->|no| E[Full-table cancellation]
    E --> F[Delete k tracked occurrences plus incoming one]
    F --> G[Each round accounts for k plus 1 items]
    G --> H[D at most floor of n over k plus 1]
    H --> I[For every key zero to D occurrences cancelled]
    I --> J[Stored count is lower bound]
    J --> K[Frequency above n over k plus 1 must survive]
    A --> L{Negative or malformed update?}
    L -->|yes| M[Cancellation interpretation fails]
    classDef navy fill:#17365D,color:#fff,stroke:#17365D;
    classDef teal fill:#147D84,color:#fff,stroke:#0D565B;
    classDef purple fill:#6C3BAA,color:#fff,stroke:#472675;
    classDef crimson fill:#C6284D,color:#fff,stroke:#861B35;
    class A,B,C navy;
    class D,E,F,G,H purple;
    class I,J,K teal;
    class L,M crimson;
One Misra-Gries cancellation round Three tracked keys and one new key form a four-item cancellation group when three counters are full. Before: k = 3 fullA:4B:2C:1new Dgroup: A + B + C + D Cancel one each4→3, 2→1, 1→0D increases by 1C removed; D not storedfour stream items accounted AfterA:3B:1residual counterslower bounds retainedproof accountingincoming key

With at most \(k\) counters and \(D\) full-table cancellations, Misra–Gries maintains \(0\le f_i-c_i\le D\le\lfloor n/(k+1)\rfloor\) for every key. Therefore every item with \(f_i>n/(k+1)\) is retained, but items exactly at the threshold may disappear and retained items still require verification to remove false positives.

Space-Saving Replacement and Error Certificates

Space-Saving also keeps \(k\) entries, each containing key, estimate \(\widehat f\), and error \(\varepsilon\). A tracked arrival increments its estimate. A free slot gets estimate one and error zero. When the table is full and an unseen \(x\) arrives, find an entry of minimum estimate \(m\), replace its key by \(x\), and store \((\widehat f_x,\varepsilon_x)=(m+1,m)\).

The inherited \(m\) is not claimed as observed frequency of \(x\); it is uncertainty. For every tracked key, \[ \widehat f_i-\varepsilon_i\le f_i\le\widehat f_i. \] The lower endpoint counts occurrences definitely seen since insertion; the upper endpoint allows for occurrences before tracking. For an untracked key, its frequency is at most the current minimum estimate. The sum of table estimates equals the processed stream length once the table is full (and also before full if all mass is represented), so the minimum is at most \(n/k\). Consequently the maximum overestimate is bounded by roughly \(n/k\), and any item with frequency greater than \(n/k\) must be tracked.

Example with \(k=2\): process \(A,A,B,C\). After \(A,A,B\), entries are \(A:(2,0)\) and \(B:(1,0)\). On \(C\), replace \(B\), producing \(C:(2,1)\). The certificate says \(1\le f_C\le2\); exact \(f_C=1\). A later \(C\) yields \(C:(3,1)\), hence \(2\le f_C\le3\), exact \(2\). The estimate stays an upper bound while the certified interval narrows proportionally for a growing key.

Tie-breaking among equal minima can change which light key is stored, but not the invariant if a true minimum is selected. A stale heap entry, overflow, or replacing a nonminimum entry can break the global error bound. SS is often empirically stronger at ranking heavy items than MG because it immediately admits new contenders, though MG's cancellation proof is especially transparent and its counters are lower bounds.

Worked Example

Space-Saving Replacement and Error Certificates

Trace SS with \(k=2\) on \(A,A,B,C,C,A,D\).

  1. After \(A,A,B\): \(A:(2,0)\), \(B:(1,0)\).
  2. \(C\) replaces minimum \(B\): \(C:(2,1)\). Verify \(1\le f_C=1\le2\).
  3. The next \(C\) increments it: \(C:(3,1)\), certifying \(2\le f_C\le3\).
  4. \(A\) increments to \(A:(3,0)\). On \(D\), either tied minimum may be replaced. If \(A\) is replaced, \(D:(4,3)\) and \(C:(3,1)\); if \(C\) is replaced, \(D:(4,3)\) and \(A:(3,0)\).
  5. Independently count exact totals \(A=3,B=1,C=2,D=1\) and verify every retained interval.
  6. Perturb the algorithm by setting replacement error to zero. The new entry \(D:(4,0)\) falsely claims \(4\le f_D\), immediately exposing why inherited error is essential.
from collections import Counter

class MisraGries:
    def __init__(self, capacity):
        if capacity < 1:
            raise ValueError("capacity must be positive")
        self.k = capacity
        self.counts = {}
        self.cancellations = 0

    def update(self, key):
        if key in self.counts:
            self.counts[key] += 1
        elif len(self.counts) < self.k:
            self.counts[key] = 1
        else:
            self.cancellations += 1
            for candidate in list(self.counts):
                self.counts[candidate] -= 1
                if self.counts[candidate] == 0:
                    del self.counts[candidate]

class SpaceSaving:
    def __init__(self, capacity):
        if capacity < 1:
            raise ValueError("capacity must be positive")
        self.k = capacity
        self.entries = {}  # key -> [estimate, error]

    def update(self, key):
        if key in self.entries:
            self.entries[key][0] += 1
        elif len(self.entries) < self.k:
            self.entries[key] = [1, 0]
        else:
            victim = min(self.entries, key=lambda x: (self.entries[x][0], str(x)))
            minimum = self.entries.pop(victim)[0]
            self.entries[key] = [minimum + 1, minimum]

def verify(stream, capacity):
    exact = Counter(stream)
    mg, ss = MisraGries(capacity), SpaceSaving(capacity)
    for key in stream:
        mg.update(key)
        ss.update(key)

    n = len(stream)
    assert mg.cancellations <= n // (capacity + 1)
    for key, truth in exact.items():
        stored = mg.counts.get(key, 0)
        assert 0 <= truth - stored <= mg.cancellations
        if truth > n / (capacity + 1):
            assert key in mg.counts

    for key, (estimate, error) in ss.entries.items():
        assert estimate - error <= exact[key] <= estimate
    for key, truth in exact.items():
        if truth > n / capacity:
            assert key in ss.entries
    return exact, mg, ss

stream = list("aaaaaaaaaabbbbbccdefghijk")
exact, mg, ss = verify(stream, 3)

verify([], 2)
verify(list("abcabcabcabc"), 1)
verify(list("abcdefgh") + ["hot"] * 9 + list("ijklmnop"), 3)

try:
    MisraGries(0)
    raise AssertionError("zero capacity accepted")
except ValueError:
    pass

print("exact heavy keys:", exact.most_common(3))
print("MG:", mg.counts, "cancellations:", mg.cancellations)
print("SS:", ss.entries)
MethodStream and assumptionsStored meaningDeterministic guaranteeUpdate costStrengthFailure modePrefer when
Misra–Gries, \(k\) countersUnit positive arrivalsLower count \(c_i\) plus global \(D\)\(0\le f_i-c_i\le D\le n/(k+1)\)\(O(k)\) naive; \(O(1)\) amortized/lazy variantsSimple cancellation proofOff-by-one convention; signed updatesTransparent guarantees and candidate discovery
Space-Saving, \(k\) countersUnit positive arrivals; true minimum replacementUpper estimate and per-entry error\(\widehat f_i-\varepsilon_i\le f_i\le\widehat f_i\); heavy candidates above \(n/k\)\(O(k)\) scan or \(O(\log k)\) heapStrong practical rankingStale minimum or lost certificateOnline top-key monitoring
Exact mapPositive or signed updatesExact frequencyNo approximationExpected \(O(1)\), memory \(O(u)\)Exact auditUnbounded distinct-key memorySmall domains or second-pass verification
Count-Min SketchNonnegative frequencies; valid hashesOne-sided hashed estimateProbabilistic additive \(\ell_1\) error\(O(d)\)Mergeable point queriesCollisions and hash attacksQuerying arbitrary keys, not just candidates
Heap over exact mapExact map plus ordering structureExact top-\(k\)Exact if both structures remain consistent\(O(\log k)\) after exact updateExact rankingStill needs \(O(u)\) mapMemory is not the bottleneck

Tracking Hot Keys with Bounded Tables

In a teaching setting, MG with two counters and colored tokens makes the invariant physical: whenever a third distinct token arrives to a full table, remove one token of every represented color plus the newcomer. Counting removed groups proves the error bound.

In production, imagine an API gateway processing \(5\times10^7\) successful request events per minute and reporting hot route–tenant pairs. Space-Saving can maintain a small online ranking with per-entry uncertainty. A verification tier then exact-counts the reported candidates for alerting. The capacity follows the smallest frequency fraction worth detecting: \(k\) should exceed the reciprocal threshold, with operational headroom for near-threshold keys.

MG may be preferable in a pipeline where the proof and a conservative lower count matter more than ranking quality. Neither standard algorithm should be selected when events include retractions or negative weights. For distributed aggregation, arbitrary table merging is not simply table addition; use a proven mergeable summary procedure or centralize updates. Evidence that invalidates deployment includes certificate violations against sampled exact counts, candidate misses above the theorem threshold, counter overflow, non-unit events entering the path, or error dominated by key-canonicalization mistakes.

An adversary can exploit a small table by sending many distinct light keys around a target. The theorem still holds for a target above its strict threshold, but near-threshold candidates may churn and reported rankings may become operationally noisy. Rate limits, identity normalization, exact verification, and monitoring distinct-key velocity are trust-boundary controls.

Bounded frequent-item counters in a monitoring system Canonical positive events enter bounded candidate tables, then candidate estimates are verified before alerts, with invalid updates and overflow marked as failure boundaries. Event edgecanonical keyunit positive eventreject signed input Bounded tableMG cancellation or SScandidates + certificateswatch overflow + churn Decision tierexact candidate verifyrank, alert, retainaudit missed heavy keys trusted contractsummary statefailure boundary
Misra-Gries & Space-Saving Invariants: Tracking Hot Keys with Bounded Tables
flowchart TD
    A[Define heavy threshold and decision cost] --> B{Unit positive stream?}
    B -->|no| C[Reject standard MG and SS]
    B -->|yes| D{Need transparent lower counts?}
    D -->|yes| E[Evaluate Misra-Gries]
    D -->|no| F{Need strong online ranking?}
    F -->|yes| G[Evaluate Space-Saving]
    F -->|no| H[Compare exact or sketch alternatives]
    E --> I[Choose capacity from threshold]
    G --> I
    I --> J[Validate against exact sampled windows]
    J --> K{Candidate and certificate checks pass?}
    K -->|no| L[Reject resize or repair pipeline]
    K -->|yes| M[Deploy with exact candidate verification]
    M --> N[Monitor churn overflow and stream model]
    N --> O{Assumptions still hold?}
    O -->|yes| N
    O -->|no| L
    classDef navy fill:#17365D,color:#fff,stroke:#17365D;
    classDef teal fill:#147D84,color:#fff,stroke:#0D565B;
    classDef purple fill:#6C3BAA,color:#fff,stroke:#472675;
    classDef crimson fill:#C6284D,color:#fff,stroke:#861B35;
    class A,B,D,F,H navy;
    class E,G,I purple;
    class J,M,N teal;
    class C,K,L,O crimson;
Case Study

Tracking Hot Keys with Bounded Tables: Misra-Gries & Space-Saving Invariants

Scenario: an API platform observes 50 million unit request events per minute and must identify route–tenant pairs exceeding 0.1% of traffic. It can retain 2,000 entries and replay a compact candidate audit log.

  1. The threshold suggests more than \(1/0.001=1000\) counters; 2,000 provides margin for near-threshold competition.
  2. Choose SS for online ranking and per-candidate intervals; run MG in shadow initially to compare candidate stability.
  3. Enforce a canonical route–tenant key, unit positive events, 64-bit counters, deterministic tie-breaking, and versioned configuration.
  4. Across 30 peak windows, compare candidates with exact counts. Check every SS interval, confirm no key above \(n/k\) is absent, measure churn, and test overflow headroom.
  5. Stress a burst of unique keys and one key just above the threshold. The true heavy key must remain a candidate, while light-key ordering may churn.
  6. Selection decision: deploy SS with exact candidate verification if interval and recall invariants always pass. Reject or redesign if retractions enter the stream, exact audits violate certificates, or distributed merge requirements lack a proven procedure.

Trace and Extend Frequent-Item Counters

Mastery begins with stating the counter convention before quoting a threshold. Reconstruct MG from its \(k+1\)-item cancellation groups, derive \(D\le n/(k+1)\), and turn that into both an interval and a candidate theorem. Then reconstruct SS replacement, explain why the old minimum becomes error, and prove the stored interval by induction.

Practice should include exact traces, not only code. Record the entire table after each arrival, MG cancellation count, and every SS error field. Compare with an exact frequency map. Debug variants that insert the incoming MG key after decrement, forget to delete zero counters, reset SS error to zero, replace a nonminimum entry, or use a too-small numeric type. Each defect should be tied to a failed proof step.

For extension, study weighted positive updates, mergeable frequent-item summaries, and verification with Count-Min or exact second passes. Do not assume a unit algorithm automatically supports these variants. The next conceptual bridge is from deterministic candidate retention to probabilistic point-query sketches and distributed summary composition.

Practice

Practice: Trace and Extend Frequent-Item Counters

Use stream \(A,B,A,C,D,A,B,E,A,C,A\) with \(k=3\).

  1. Recall (2 points): define cancellation, residual stream, candidate, replacement, and certificate.
  2. Trace MG (5): show the table and \(D\) after every item. Verify \(0\le f_i-c_i\le D\) for all five keys.
  3. Trace SS (5): record \((\widehat f,\varepsilon)\) after every item. Verify each final interval against exact counts.
  4. Proof (5): show that MG cancellation groups are disjoint and prove the heavy-candidate theorem. Then prove the SS interval inductively.
  5. Debug (3): set a replacement certificate to zero and produce the first false lower bound.
  6. Compare (3): explain which stored values are lower bounds, upper bounds, and uncertainty; decide which method better serves ranking.
  7. Stretch (4): design a weighted-positive variant or a merge plan, explicitly stating the new invariant and one counterexample to a naive approach.

Completion criteria: all states auditable, threshold convention explicit, exact oracle supplied, boundary equality tested, and invalid signed update rejected. Rubric: 24–27 professional mastery; 18–23 sound with minor proof gaps; 12–17 revisit invariants; below 12 retrace manually. Reflection: does your real system need candidate recall, approximate rank, exact frequency, arbitrary-key queries, or mergeability?

Use Misra–Gries when a cancellation proof and lower counters fit the task; use Space-Saving when online ranking and per-entry upper estimates with error certificates are more useful. Always state the \(k\)-counter convention, require positive-stream semantics, verify candidates before high-stakes action, and treat weighted updates or distributed merges as separate algorithms requiring fresh invariants.