<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Data-Structures on CS Theorems</title><link>https://cs.lozic.me/areas/data-structures/</link><description>Recent content in Data-Structures on CS Theorems</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Fri, 12 Nov 2027 12:00:00 +0100</lastBuildDate><atom:link href="https://cs.lozic.me/areas/data-structures/index.xml" rel="self" type="application/rss+xml"/><item><title>Bloom Filters</title><link>https://cs.lozic.me/posts/t073-bloom-filters/</link><pubDate>Fri, 12 Nov 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t073-bloom-filters/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Every request to your service checks whether a user ID exists before doing
anything else. The check hits the database. Ninety-eight percent of the time the
answer is no, because most of the traffic is bots probing for accounts that were
never created.&lt;/p&gt;</description></item><item><title>Consistent Hashing</title><link>https://cs.lozic.me/posts/t072-consistent-hashing/</link><pubDate>Fri, 29 Oct 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t072-consistent-hashing/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You shard a cache across ten servers with the obvious rule:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;servers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;servers&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It works. Then you add an eleventh server, and &lt;code&gt;% 10&lt;/code&gt; becomes &lt;code&gt;% 11&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Every key now maps somewhere else. Not one tenth of them — essentially all of
them. A key landing on the same server after the change is a coincidence with
probability about $1/11$, so roughly 91% of your cache is instantly invalid.
Every request misses, every miss hits the database, and the database, sized for
a 95% cache hit rate, now receives twenty times its provisioned load and falls
over.&lt;/p&gt;</description></item><item><title>Streaming Lower Bounds and Sketching</title><link>https://cs.lozic.me/posts/t105-streaming-lower-bounds-and-sketching/</link><pubDate>Fri, 30 Apr 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t105-streaming-lower-bounds-and-sketching/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Product wants the daily unique-visitor count. You have a firehose of events.&lt;/p&gt;
&lt;p&gt;The obvious implementation is a set. Add each visitor ID, report the size. At a
billion distinct IDs, eight bytes each, that is 8 GB before any hash table
overhead, and in practice a &lt;code&gt;HashSet&lt;/code&gt; will cost you two to three times that.
Per day. Per dimension you want to slice by. Multiply by country, by platform,
by campaign, and the memory bill is absurd for a number nobody looks at past two
significant figures.&lt;/p&gt;</description></item><item><title>Universal Hashing</title><link>https://cs.lozic.me/posts/t104-universal-hashing/</link><pubDate>Fri, 23 Apr 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t104-universal-hashing/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Your service went down under a hash collision attack.&lt;/p&gt;
&lt;p&gt;Somebody noticed your web framework put POST parameters into a hash table, found
thousands of distinct keys colliding under its hash function, and posted a form
with 20,000 of them. Every insert walked a chain. Quadratic behaviour, one CPU
pinned per request, service dead. This actually happened, across PHP, Python,
Ruby, Java and .NET in 2011, and again against Rust&amp;rsquo;s default &lt;code&gt;HashMap&lt;/code&gt; before
it switched to SipHash.&lt;/p&gt;</description></item><item><title>Amortized Analysis and the Potential Method</title><link>https://cs.lozic.me/posts/t006-amortized-analysis-and-the-potential-method/</link><pubDate>Fri, 11 Dec 2026 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t006-amortized-analysis-and-the-potential-method/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You have a dynamic array. &lt;code&gt;push&lt;/code&gt; writes one element and bumps a counter, which
is clearly $O(1)$ — except when the array is full, in which case it allocates a
new buffer of twice the size, copies every element across, and frees the old
one. That is $O(n)$.&lt;/p&gt;</description></item><item><title>The Birthday Bound</title><link>https://cs.lozic.me/posts/t074-the-birthday-bound/</link><pubDate>Fri, 06 Nov 2026 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t074-the-birthday-bound/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You need a short ID for uploads. Eight hex characters feels generous, so you
take the first 32 bits of a hash and move on.&lt;/p&gt;
&lt;p&gt;At about 80,000 uploads, two files collide, and one of them silently overwrites
the other, and the bug report says the customer&amp;rsquo;s invoice contains someone
else&amp;rsquo;s line items.&lt;/p&gt;</description></item></channel></rss>