Skip to content

Quadratic probing

Probing 1, 4, 9, … slots away breaks up linear probing’s long runs, though keys with the same home still follow the same path.

Helps to know firstLinear probing

Helps to know first
This topic

First, the picture

The same eight keys as in linear probing, but a key that collides now jumps further each time: 1 slot, then 4, then 9. Watch 81 escape the block.

Jumping further to find a seat

The same eight keys, probing 1, 4, 9 slots on

#define M 11 #ifndef KEYS#define KEYS 8#endif enum state { EMPTY, FULL, DELETED }; struct slot {    int key;    enum state state;}; static struct slot table[M];static int probes = 0; bool put(int key){    int target = -1;    for (int i = 0; i < M; i++) {        int s = (key % M + i * i) % M;        probes++;        if (table[s].state == FULL && table[s].key == key)            return true;        if (table[s].state == DELETED && target < 0)            target = s;        if (table[s].state == EMPTY) {            if (target < 0)                target = s;            break;        }    }    if (target < 0)        return false;    table[target].key = key;    table[target].state = FULL;    return true;} int find(int key){    for (int i = 0; i < M; i++) {        int s = (key % M + i * i) % M;        probes++;        if (table[s].state == EMPTY)            return -1;        if (table[s].state == FULL && table[s].key == key)            return s;    }    return -1;} void remove_key(int key){    int s = find(key);    if (s >= 0)        table[s].state = DELETED;} int main(void){    const int keys[9] = { 26, 37, 5, 59, 16, 72, 81, 9, 15 };    for (int i = 0; i < KEYS; i++) {        probes = 0;        put(keys[i]);        printf("put %d: %d probes\n", keys[i], probes);    }    probes = 0;    int a = find(48);    printf("find 48: %d after %d probes\n", a, probes);    remove_key(37);    probes = 0;    int b = find(59);    printf("find 59: slot %d after %d probes\n", b, probes);    return 0;}

main has started: an empty table of 11 slots.

key
–
probes
0
α
0.00

Output

0.00 / 31.90 s
Describe this picture

A row of eleven slots, numbered 0 to 10, named struct slot table[11], with the code beside them, the line about to run marked. The clip takes about 32 seconds. The keys 26, 37, 5, 59, 16, 72, 81 and 9 are put in turn, each starting at its home slot, the key mod 11. A marker s stands on each slot probed; a taken slot is marked, and an arc joins it to the slot tried next, the arcs growing longer: 59, home 4, tries 4, then 5, then 8. 81, also home 4, follows exactly the same jumps, then one more of 9 slots, which wraps round to slot 2, outside the block of full slots. At the end slot 2 holds 81, slots 4 to 10 hold 26, 37, 5, 72, 59, 16 and 9, and slots 0, 1 and 3 are empty. Then the search for 48 jumps among slots 4, 5, 8, 2, 9 and 7 and gives up after 11 probes without ever reaching an empty slot. 37 is removed, leaving “del” in slot 5, and the search for 59 passes it and finds 59 in slot 8 after 3 probes. Under the picture are one sentence on the current step and the readouts “key”, “probes” and “α”. The transport plays and pauses, steps one beat back or forward, and scrubs; a paused step is kept in the page address as quadratic-probing.step.

Jumping further

Linear probing’s trouble is that a cluster catches every key whose home falls in it. Quadratic probing jumps over it: probe i goes i² slots from home,

si=(k mod m+i2) mod m,i=0,1,2,…s_i = (k \bmod m + i^2) \bmod m, \qquad i = 0, 1, 2, \dots

so a key tries its home, then 1, 4, 9, 16, … slots on, wrapping round. Keys with nearby homes soon take different paths, and long runs of full slots break up.

The code and its cost

The program is linear probing’s with two edits. In both put and find, the probe slot becomes

        int s = (key % M + i * i) % M;

and the keys gain a ninth, 15, which main puts only when built with -DKEYS=9:

    const int keys[9] = { 26, 37, 5, 59, 16, 72, 81, 9, 15 };

With the eight keys:

Key26375591672819
Probes, quadratic12233242
Probes, linear12244473
Slot456897210

19 probes in all, against linear probing’s 27. 81 goes 4, 5, 8, then 4 + 9 = 13, which is slot 2.

Secondary clustering

The four keys with home 4 (26, 37, 59 and 81) still follow one path: 4, 5, 8, 2, … Each takes one more step along it than the one before. Keys with the same home share their whole probe sequence, because it depends only on the home. That is secondary clustering: milder than linear probing’s, since keys with different homes no longer pile onto one run.

The half-full guarantee

Quadratic probing does not visit every slot. With m prime, the first (m + 1)/2 probes reach different slots, so a table at most half full always has room for a new key. Beyond half full, a free slot may be unreachable.

Worked example

Which slots a key can reach. From home 4 in 11 slots, i² mod 11 for i = 0, 1, 2, … is 0, 1, 4, 9, 5, 3, 3, 5, 9, 4, 1, so the probes go to slots 4, 5, 8, 2, 9, 7, 7, 9, 2, 8, 5. Only 6 of the 11 slots are ever probed: 2, 4, 5, 7, 8 and 9.

Fifteen does not fit. In the lesson’s table all six of those slots are full. Built with -DKEYS=9, the program tries to put 15, home 4, and prints put 15: 11 probes: every probe hits a full slot, and put gives up, although slots 0, 1 and 3 are free. The table is 8/11 full, more than half, so the guarantee does not hold. The search for 48 fails the same way, after 11 probes.

One check. How many probes does 81 take by linear probing? (7.) By quadratic? (4.)

Where it’s used

Open-addressing tables in libraries, usually with power-of-two sizes and triangular steps (1, 3, 6, …), which do visit every slot.

Reference card

Code or ideaMeaning
(key % M + i * i) % Mprobe i: home, then 1, 4, 9, … slots on
secondary clusteringkeys with the same home share their path
m prime, α ≤ 1/2a new key always finds a slot
beyond half fulla free slot may be unreachable
eight keys here19 probes, against linear probing’s 27

Platform: C11, gcc on x86-64 Linux: int 4 bytes, little-endian. Addresses in the pictures are short stand-ins, by one rule for the whole course; sizes are the real ones.

End of the lesson

Where to go next.

New lessons by email

Are you 13 or over?

Accounts and email updates are for people aged 13 or over. We keep only your answer, never your date of birth.

Phasorium

Account

Sign inWith Google, GitHub or your email

Subjects

Site

Look