Cuckoo Hashing Worst case O(1) Lookup! (original) (raw)

Last Updated : 23 Jul, 2025

**Background :

There are three basic operations that must be supported by a hash table (or a dictionary):

Collisions are very likely even if we have a big table to store keys. Using the results from the birthday paradox: with only 23 persons, the probability that two people share the same birth date is 50%! There are 3 general strategies towards resolving hash collisions:

Although above solutions provide expected lookup cost as O(1), the expected worst-case cost of a lookup in Open Addressing (with linear probing) is Ω(log n) and Θ(log n / log log n) in simple chaining (Source : Standford Lecture Notes). To close the gap of expected time and worst case expected time, two ideas are used:

**Cuckoo Hashing :

Cuckoo hashing applies the idea of multiple-choice and relocation together and guarantees O(1) worst case lookup time!

**Insertion is expected O(1) (amortized) with high probability, even considering the possibility of rehashing, as long as the number of keys is kept below half of the capacity of the hash table, i.e., the load factor is below 50%.

**Deletion is O(1) worst-case as it requires inspection of just two locations in the hash table.

**Illustration

**Input:

{20, 50, 53, 75, 100, 67, 105, 3, 36, 39}

**Hash Functions:

h1(key) = key%11
h2(key) = (key/11)%11

ch1

Let’s start by inserting **20 at its possible position in the first table determined by h1(20):

ch2

Next: **50

ch3

Next: **53. h1(53) = 9. But 20 is already there at 9. We place 53 in table 1 & 20 in table 2 at h2(20)

ch4

Next: **75. h1(75) = 9. But 53 is already there at 9. We place 75 in table 1 & 53 in table 2 at h2(53)

ch6

Next: **100. h1(100) = 1.

ch

Next: **67. h1(67) = 1. But 100 is already there at 1. We place 67 in table 1 & 100 in table 2

ch8

Next: **105. h1(105) = 6. But 50 is already there at 6. We place 105 in table 1 & 50 in table 2 at h2(50) = 4. Now 53 has been displaced. h1(53) = 9. 75 displaced: h2(75) = 6.

ch9

Next: **3. h1(3) = 3.

ch10

Next: **36. h1(36) = 3. h2(3) = 0.

ch11

Next: **39. h1(39) = 6. h2(105) = 9. h1(100) = 1. h2(67) = 6. h1(75) = 9. h2(53) = 4. h1(50) = 6. h2(39) = 3.
Here, the new key 39 is displaced later in the recursive calls to place 105, which it displaced.

ch12

**Implementation:

Below is the implementation of Cuckoo hashing

C++ `

// C++ program to demonstrate working of Cuckoo // hashing. #include<bits/stdc++.h>

// upper bound on number of elements in our set #define MAXN 11

// choices for position #define ver 2

// Auxiliary space bounded by a small multiple // of MAXN, minimizing wastage int hashtable[ver][MAXN];

// Array to store possible positions for a key int pos[ver];

/* function to fill hash table with dummy value

}

/* return hashed value for a key

/* function to place a key in one of its possible positions

}

/* function to print hash table contents */ void printTable() { printf("Final hash tables:\n");

for (int i=0; i<ver; i++, printf("\n"))
    for (int j=0; j<MAXN; j++)
        (hashtable[i][j]==INT_MIN)? printf("- "):
                 printf("%d ", hashtable[i][j]);

printf("\n");

}

/* function for Cuckoo-hashing keys

}

/* driver function / int main() { / following array doesn't have any cycles and hence all keys will be inserted without any rehashing */ int keys_1[] = {20, 50, 53, 75, 100, 67, 105, 3, 36, 39};

int n = sizeof(keys_1)/sizeof(int);

cuckoo(keys_1, n);

/* following array has a cycle and hence we will
   have to rehash to position every key */
int keys_2[] = {20, 50, 53, 75, 100, 67, 105,
                3, 36, 39, 6};

int m = sizeof(keys_2)/sizeof(int);

cuckoo(keys_2, m);

return 0;

}

Java

// Java program to demonstrate working of // Cuckoo hashing. import java.util.*;

class GFG {

// upper bound on number of elements in our set static int MAXN = 11;

// choices for position static int ver = 2;

// Auxiliary space bounded by a small multiple // of MAXN, minimizing wastage static int [][]hashtable = new int[ver][MAXN];

// Array to store possible positions for a key static int []pos = new int[ver];

/* function to fill hash table with dummy value

}

/* return hashed value for a key

/* function to place a key in one of its possible positions

}

/* function to print hash table contents */ static void printTable() { System.out.printf("Final hash tables:\n");

for (int i = 0; i < ver; i++, System.out.printf("\n"))
    for (int j = 0; j < MAXN; j++)
        if(hashtable[i][j] == Integer.MIN_VALUE) 
            System.out.printf("- ");
        else
            System.out.printf("%d ", hashtable[i][j]);

System.out.printf("\n");

}

/* function for Cuckoo-hashing keys

}

// Driver Code public static void main(String[] args) { /* following array doesn't have any cycles and hence all keys will be inserted without any rehashing */ int keys_1[] = {20, 50, 53, 75, 100, 67, 105, 3, 36, 39};

int n = keys_1.length;

cuckoo(keys_1, n);

/* following array has a cycle and hence we will
have to rehash to position every key */
int keys_2[] = {20, 50, 53, 75, 100, 
                67, 105, 3, 36, 39, 6};

int m = keys_2.length;

cuckoo(keys_2, m);

} }

// This code is contributed by Princi Singh

Python

upper bound on number of elements in our set

MAXN = 11

choices for position

ver = 2

Auxiliary space bounded by a small multiple

of MAXN, minimizing wastage

hashtable = [[float('inf')] * MAXN for _ in range(ver)]

Array to store possible positions for a key

pos = [0] * ver

def init_table(): """function to fill hash table with dummy value dummy value: float('inf') number of hashtables: ver""" for i in range(ver): for j in range(MAXN): hashtable[i][j] = float('inf')

def hash(function, key): """return hashed value for a key function: ID of hash function according to which key has to hashed key: item to be hashed""" if function == 1: return key % MAXN elif function == 2: return (key // MAXN) % MAXN

def place(key, table_id, cnt, n): """function to place a key in one of its possible positions table_id: table in which key has to be placed, also equal to function according to which key must be hashed cnt: number of times function has already been called in order to place the first input key n: maximum number of times function can be recursively called before stopping and declaring presence of cycle""" # if function has been recursively called max number of times, stop # and declare cycle. Rehash. if cnt == n: print(f"{key} unpositioned") print("Cycle present. REHASH.") return

# calculate and store possible positions for the key. check if key
# already present at any of the positions. If YES, return.
for i in range(ver):
    pos[i] = hash(i + 1, key)
    if hashtable[i][pos[i]] == key:
        return

# check if another key is already present at the position for the
# new key in the table
# If YES: place the new key in its position and place the older key
# in an alternate position for it in the next table
if hashtable[table_id][pos[table_id]] != float('inf'):
    dis = hashtable[table_id][pos[table_id]]
    hashtable[table_id][pos[table_id]] = key
    place(dis, (table_id + 1) % ver, cnt + 1, n)
else: # else: place the new key in its position
    hashtable[table_id][pos[table_id]] = key

def print_table(): """function to print hash table contents""" print("Final hash tables:") for i in range(ver): print() for j in range(MAXN): if hashtable[i][j] == float('inf'): print("- ", end="") else: print(f"{hashtable[i][j]} ", end="") print()

def cuckoo(keys, n): # initialize hash tables to a dummy value (float('inf')) # indicating empty position init_table()

# start with placing every key at its position in the first
# hash table according to first hash function
for i in range(n):
    cnt = 0
    place(keys[i], 0, cnt, n)

# print the final hash tables
print_table()

driver function

def main(): # following array doesn't have any cycles and # hence all keys will be inserted without any # rehashing keys_1 = [20, 50, 53, 75, 100, 67, 105, 3, 36, 39]

cuckoo(keys_1, len(keys_1))

# following array has a cycle and hence we will
# have to rehash to position every key
keys_2 = [20, 50, 53, 75, 100, 67, 105, 3, 36, 39, 6]

cuckoo(keys_2, len(keys_2))

if name == "main": main()

This code is contributed by vikramshirsath177

C#

// C# program to demonstrate working of // Cuckoo hashing. using System;

class GFG {

// upper bound on number of // elements in our set static int MAXN = 11;

// choices for position static int ver = 2;

// Auxiliary space bounded by a small // multiple of MAXN, minimizing wastage static int [,]hashtable = new int[ver, MAXN];

// Array to store // possible positions for a key static int []pos = new int[ver];

/* function to fill hash table with dummy value

}

/* return hashed value for a key

/* function to place a key in one of its possible positions

{ /* if function has been recursively called max number of times, stop and declare cycle. Rehash. */ if (cnt == n) { Console.Write("{0} unpositioned\n", key); Console.Write("Cycle present. REHASH.\n"); return; }

/* calculate and store possible positions 
* for the key. Check if key already present 
at any of the positions. If YES, return. */
for (int i = 0; i < ver; i++)
{
    pos[i] = hash(i + 1, key);
    if (hashtable[i, pos[i]] == key)
    return;
}

/* check if another key is already present 
at the position for the new key in the table
* If YES: place the new key in its position
* and place the older key in an alternate position
for it in the next table */
if (hashtable[tableID, 
          pos[tableID]] != int.MinValue)
{
    int dis = hashtable[tableID, pos[tableID]];
    hashtable[tableID, pos[tableID]] = key;
    place(dis, (tableID + 1) % ver, cnt + 1, n);
}
else // else: place the new key in its position
hashtable[tableID, pos[tableID]] = key;

}

/* function to print hash table contents */ static void printTable() { Console.Write("Final hash tables:\n");

for (int i = 0; i < ver;
         i++, Console.Write("\n"))
    for (int j = 0; j < MAXN; j++)
        if(hashtable[i, j] == int.MinValue) 
            Console.Write("- ");
        else
            Console.Write("{0} ",
                    hashtable[i, j]);

Console.Write("\n");

}

/* function for Cuckoo-hashing keys

}

// Driver Code public static void Main(String[] args) { /* following array doesn't have any cycles and hence all keys will be inserted without any rehashing */ int []keys_1 = {20, 50, 53, 75, 100, 67, 105, 3, 36, 39};

int n = keys_1.Length;

cuckoo(keys_1, n);

/* following array has a cycle and 
hence we will have to rehash to 
position every key */
int []keys_2 = {20, 50, 53, 75, 100, 
                67, 105, 3, 36, 39, 6};

int m = keys_2.Length;

cuckoo(keys_2, m);

} }

// This code is contributed by PrinciRaj1992

JavaScript

`

Output

Final hash tables:

105 unpositioned Cycle present. REHASH. Final hash tables:

**Time Complexity: O(N), the time complexity of the Cuckoo Hashing algorithm is O(N), where N is the number of keys to be stored in the hash table. This is because the algorithm requires only one pass over the list of keys to place them in the hash table.

**Auxiliary Space: O(N), the space complexity of the Cuckoo Hashing algorithm is O(N), where N is the number of keys stored in the hash table. This is because the algorithm requires an auxiliary space of size equal to the hash table, where all the keys are stored.

Generalizations of cuckoo hashing that use more than 2 alternative hash functions can be expected to utilize a larger part of the capacity of the hash table efficiently while sacrificing some lookup and insertion speed. Example: if we use 3 hash functions, it’s safe to load 91% and still be operating within expected bounds.