Linear Probing in Hash Tables

Last Updated : 15 Jan, 2026

In Open Addressing, all elements are stored directly in the hash table itself. Therefore, the size of the hash table must be greater than the total number of keys. To maintain good performance, the load factor (number of keys divided by table size) should be kept below a certain limit, usually 0.7. If needed, the table size can be increased by rehashing the existing elements. 

Insert(k): The hash function is applied to the key to generate an index. If that slot is occupied, probing continues until an empty or deleted slot is found, and the key is inserted there.

Search(k): The hash function generates the starting index, and probing continues until the key is found or an empty slot is encountered.

Delete(k): Instead of removing an element completely, its slot is marked as "deleted" using a dummy node (key = –1, value = –1). This ensures that searching does not stop prematurely and that future insert operations can reuse deleted slots.

This process ensures that every key is mapped to a valid index within the hash table and that values are stored based on the position generated by the hash function. Searching, insertion, and deletion take O(1) average time, but in the worst case, these operations may take O(n) time if the table becomes too full or has many deleted slots.

Implementation:

Try it on GfG Practice
redirect icon
CPP
#include <bits/stdc++.h>
using namespace std;

// Class representing a single node in the hash map
class HashNode {
public:
    int key, value;

    // Constructor to initialize key-value pair
    HashNode(int k, int v) {
        key = k;
        value = v;
    }
};

// HashMap class using open addressing with linear probing
class HashMap {
    int capacity;       // Maximum size of the hash table
    int size;           // Current number of elements in the map
    HashNode** arr;     // Array of pointers to HashNode
    HashNode* dummy;    // Dummy node to mark deleted positions

public:
    // Constructor
    HashMap() {
        capacity = 20;  // Initial capacity
        size = 0;       // Initially empty
        arr = new HashNode*[capacity];

        // Initialize all positions as NULL
        for (int i = 0; i < capacity; i++)
            arr[i] = NULL;

        // Dummy node represents a deleted slot
        dummy = new HashNode(-1, -1);
    }

    // Simple hash function (modulo operation)
    int hashCode(int key) {
        return key % capacity;
    }

    // Rehashing function to resize the table when load factor >= 0.7
    void rehash() {
        HashNode** oldArr = arr;
        int oldCap = capacity;

        capacity *= 2;   // Double the capacity
        size = 0;        // Reset size
        arr = new HashNode*[capacity];
        for (int i = 0; i < capacity; i++)
            arr[i] = NULL;

        // Re-insert all old elements into the new array
        for (int i = 0; i < oldCap; i++) {
            if (oldArr[i] != NULL && oldArr[i]->key != -1) {
                insertNode(oldArr[i]->key, oldArr[i]->value);
            }
        }
    }

    // Insert a key-value pair into the hash map
    void insertNode(int key, int value) {
        // Rehash if load factor exceeds 0.7
        if ((double)size / capacity >= 0.7)
            rehash();

        HashNode* temp = new HashNode(key, value);
        int hashIndex = hashCode(key);
        int counter = 0;

        // Linear probing to find an empty or deleted slot
        while (arr[hashIndex] != NULL &&
               arr[hashIndex]->key != key &&
               arr[hashIndex]->key != -1) {

            if (counter++ >= capacity)  // Prevent infinite loop
                return;

            hashIndex = (hashIndex + 1) % capacity;
        }

        // If inserting into empty or deleted slot, increase size
        if (arr[hashIndex] == NULL || arr[hashIndex]->key == -1)
            size++;

        arr[hashIndex] = temp;  // Insert node
    }

    // Delete a key from the hash map
    int deleteNode(int key) {
        int hashIndex = hashCode(key);
        int counter = 0;

        // Linear probing to find the key
        while (arr[hashIndex] != NULL) {

            if (counter++ >= capacity)
                return -1;  // Key not found

            if (arr[hashIndex]->key == key) {
                int val = arr[hashIndex]->value;
                delete arr[hashIndex];     // Free memory
                arr[hashIndex] = dummy;    // Mark as deleted
                size--;
                return val;
            }

            hashIndex = (hashIndex + 1) % capacity;
        }

        return -1;  // Key not found
    }

    // Get value for a key
    int get(int key) {
        int hashIndex = hashCode(key);
        int counter = 0;

        // Linear probing to find the key
        while (arr[hashIndex] != NULL) {

            if (counter++ >= capacity)
                return -1;  // Key not found

            if (arr[hashIndex]->key == key)
                return arr[hashIndex]->value;

            hashIndex = (hashIndex + 1) % capacity;
        }

        return -1;  // Key not found
    }

    // Get current number of elements in the map
    int sizeofMap() {
        return size;
    }

    // Check if the map is empty
    bool isEmpty() {
        return size == 0;
    }

    // Display all key-value pairs
    void display() {
        for (int i = 0; i < capacity; i++) {
            if (arr[i] != NULL && arr[i]->key != -1)
                cout << arr[i]->key << " " << arr[i]->value << endl;
        }
    }
};

int main() {
    HashMap h;

    // Insert elements
    h.insertNode(1, 10);
    h.insertNode(2, 20);
    h.insertNode(3, 30);
    h.insertNode(22, 220);
    h.insertNode(42, 420);

    cout << "Hash Map Elements:\n";
    h.display();  // Display elements

    cout << "\nSize of map: " << h.sizeofMap() << endl;

    // Delete a key
    cout << "\nDeleting key 2 -> " << h.deleteNode(2) << endl;

    cout << "Size after deletion: " << h.sizeofMap() << endl;

    // Access values
    cout << "\nValue of key 3: " << h.get(3) << endl;
    cout << "Value of key 2: " << h.get(2) << endl;  // Key 2 deleted

    // Check if map is empty
    cout << "\nIs map empty? " << (h.isEmpty() ? "Yes" : "No") << endl;

    return 0;
}
Java
import java.lang.*;

class hashNode {
    int key;
    int value;

    // constructor
    public hashNode(int key, int value) {
        this.key = key;
        this.value = value;
    }
}

class hashMap {
    hashNode[] arr;
    int capacity;
    int size;
    hashNode dummy;

    // constructor
    public hashMap() {
        capacity = 20;
        size = 0;
        arr = new hashNode[capacity];
        dummy = new hashNode(-1, -1);
    }

    // hash function
    int hashCode(int key) {
        return key % capacity;
    }

    // insert key-value pair
    void insertNode(int key, int value) {
        hashNode temp = new hashNode(key, value);
        int hashIndex = hashCode(key);

        while (arr[hashIndex] != null &&
               arr[hashIndex].key != key &&
               arr[hashIndex].key != -1) {
            hashIndex++;
            hashIndex %= capacity;
        }

        if (arr[hashIndex] == null || arr[hashIndex].key == -1)
            size++;
        arr[hashIndex] = temp;
    }

    // delete by key
    int deleteNode(int key) {
        int hashIndex = hashCode(key);

        while (arr[hashIndex] != null) {
            if (arr[hashIndex].key == key) {
                hashNode temp = arr[hashIndex];
                arr[hashIndex] = dummy;
                size--;
                return temp.value;
            }
            hashIndex++;
            hashIndex %= capacity;
        }

        return -1;
    }

    // get value by key
    int get(int key) {
        int hashIndex = hashCode(key);
        int counter = 0;

        while (arr[hashIndex] != null) {
            if (counter++ > capacity)
                return -1;

            if (arr[hashIndex].key == key)
                return arr[hashIndex].value;
            hashIndex++;
            hashIndex %= capacity;
        }

        return -1;
    }

    // size of map
    int sizeofMap() {
        return size;
    }

    // check if map is empty
    boolean isEmpty() {
        return size == 0;
    }

    // display key-value pairs
    void display() {
        for (int i = 0; i < capacity; i++) {
            if (arr[i] != null && arr[i].key != -1) {
                System.out.println(arr[i].key +
                " " + arr[i].value);
            }
        }
    }

    public static void main(String[] args) {
        hashMap h = new hashMap();
        h.insertNode(1, 1);
        h.insertNode(2, 2);
        h.insertNode(2, 3);
        h.display();
        System.out.println(h.sizeofMap());
        System.out.println(h.deleteNode(2));
        System.out.println(h.sizeofMap());
        System.out.println(h.isEmpty());
        System.out.println(h.get(2));
    }
}
Python
class hashNode:
    
    # constructor
    def __init__(self, key, value):
        self.key = key
        self.value = value

class hashMap:
    
    # constructor
    def __init__(self):
        self.capacity = 20
        self.size = 0
        self.arr = [None] * self.capacity
        self.dummy = hashNode(-1, -1)

    # hash function
    def hashCode(self, key):
        return key % self.capacity

    # insert key-value pair
    def insertNode(self, key, value):
        temp = hashNode(key, value)
        hashIndex = self.hashCode(key)

        while self.arr[hashIndex] is not None and \
              self.arr[hashIndex].key != key and \
              self.arr[hashIndex].key != -1:
            hashIndex = (hashIndex + 1) % self.capacity

        if self.arr[hashIndex] is None or \
                    self.arr[hashIndex].key == -1:
            self.size += 1
        self.arr[hashIndex] = temp

    # delete by key
    def deleteNode(self, key):
        hashIndex = self.hashCode(key)

        while self.arr[hashIndex] is not None:
            if self.arr[hashIndex].key == key:
                temp = self.arr[hashIndex]
                self.arr[hashIndex] = self.dummy
                self.size -= 1
                return temp.value
            hashIndex = (hashIndex + 1) % self.capacity

        return -1

    # get value by key
    def get(self, key):
        hashIndex = self.hashCode(key)
        counter = 0

        while self.arr[hashIndex] is not None:
            if counter > self.capacity:
                return -1
            if self.arr[hashIndex].key == key:
                return self.arr[hashIndex].value
            hashIndex = (hashIndex + 1) % self.capacity
            counter += 1

        return -1

    # return map size
    def sizeofMap(self):
        return self.size

    # check if map is empty
    def isEmpty(self):
        return self.size == 0

    # display all key-value pairs
    def display(self):
        for node in self.arr:
            if node is not None and node.key != -1:
                print(f"{node.key} {node.value}")

if __name__ == "__main__":
    h = hashMap()
    h.insertNode(1, 1)
    h.insertNode(2, 2)
    h.insertNode(2, 3)
    h.display()
    print(h.sizeofMap())
    print(h.deleteNode(2))
    print(h.sizeofMap())
    print(str(h.isEmpty()).lower())
    print(h.get(2))
C#
using System;

class hashNode {
    public int key;
    public int value;

    // constructor
    public hashNode(int key, int value) {
        this.key = key;
        this.value = value;
    }
}

class hashMap {
    hashNode[] arr;
    int capacity;
    int size;
    hashNode dummy;

    // constructor
    public hashMap() {
        capacity = 20;
        size = 0;
        arr = new hashNode[capacity];
        dummy = new hashNode(-1, -1);
    }

    // hash function
    int hashCode(int key) {
        return key % capacity;
    }

    // insert key-value pair
    public void insertNode(int key, int value) {
        hashNode temp = new hashNode(key, value);
        int hashIndex = hashCode(key);

        while (arr[hashIndex] != null &&
               arr[hashIndex].key != key &&
               arr[hashIndex].key != -1) {
            hashIndex++;
            hashIndex %= capacity;
        }

        if (arr[hashIndex] == null || arr[hashIndex].key == -1)
            size++;
        arr[hashIndex] = temp;
    }

    // delete by key
    public int deleteNode(int key) {
        int hashIndex = hashCode(key);

        while (arr[hashIndex] != null) {
            if (arr[hashIndex].key == key) {
                hashNode temp = arr[hashIndex];
                arr[hashIndex] = dummy;
                size--;
                return temp.value;
            }
            hashIndex++;
            hashIndex %= capacity;
        }

        return -1;
    }

    // get value by key
    public int get(int key) {
        int hashIndex = hashCode(key);
        int counter = 0;

        while (arr[hashIndex] != null) {
            if (counter++ > capacity)
                return -1;

            if (arr[hashIndex].key == key)
                return arr[hashIndex].value;
            hashIndex++;
            hashIndex %= capacity;
        }

        return -1;
    }

    // size of map
    public int sizeofMap() {
        return size;
    }

    // check if map is empty
    public bool isEmpty() {
        return size == 0;
    }

    // display key-value pairs
    public void display() {
        for (int i = 0; i < capacity; i++) {
            if (arr[i] != null && arr[i].key != -1) {
                Console.WriteLine(arr[i].key + 
                                    " " + arr[i].value);
            }
        }
    }

    static void Main(string[] args) {
        hashMap h = new hashMap();
        h.insertNode(1, 1);
        h.insertNode(2, 2);
        h.insertNode(2, 3);
        h.display();
        Console.WriteLine(h.sizeofMap());
        Console.WriteLine(h.deleteNode(2));
        Console.WriteLine(h.sizeofMap());
        Console.WriteLine(h.isEmpty().
                    ToString().ToLower());
        Console.WriteLine(h.get(2));
    }
}
JavaScript
class hashNode {
    constructor(key, value) {
        this.key = key;
        this.value = value;
    }
}

class hashMap {
    constructor() {
        this.capacity = 20;
        this.size = 0;
        this.arr = new Array(this.capacity).fill(null);
        this.dummy = new hashNode(-1, -1);
    }

    hashCode(key) {
        return key % this.capacity;
    }

    insertNode(key, value) {
        let temp = new hashNode(key, value);
        let hashIndex = this.hashCode(key);

        while (this.arr[hashIndex] !== null &&
               this.arr[hashIndex].key !== key &&
               this.arr[hashIndex].key !== -1) {
            hashIndex = (hashIndex + 1) % this.capacity;
        }

        if (this.arr[hashIndex] === null || this.arr[hashIndex].key === -1)
            this.size++;
        this.arr[hashIndex] = temp;
    }

    deleteNode(key) {
        let hashIndex = this.hashCode(key);

        while (this.arr[hashIndex] !== null) {
            if (this.arr[hashIndex].key === key) {
                let temp = this.arr[hashIndex];
                this.arr[hashIndex] = this.dummy;
                this.size--;
                return temp.value;
            }
            hashIndex = (hashIndex + 1) % this.capacity;
        }

        return -1;
    }

    get(key) {
        let hashIndex = this.hashCode(key);
        let counter = 0;

        while (this.arr[hashIndex] !== null) {
            if (counter++ > this.capacity)
                return -1;

            if (this.arr[hashIndex].key === key)
                return this.arr[hashIndex].value;
            hashIndex = (hashIndex + 1) % this.capacity;
        }

        return -1;
    }

    sizeofMap() {
        return this.size;
    }

    isEmpty() {
        return this.size === 0;
    }

    display() {
        for (let i = 0; i < this.capacity; i++) {
            let node = this.arr[i];
            if (node !== null && node.key !== -1)
                console.log(`${node.key} ${node.value}`);
        }
    }
}

// Driver Code
let h = new hashMap();
h.insertNode(1, 1);
h.insertNode(2, 2);
h.insertNode(2, 3);
h.display();
console.log(h.sizeofMap());
console.log(h.deleteNode(2));
console.log(h.sizeofMap());
console.log(h.isEmpty());
console.log(h.get(2));

Output
Hash Map Elements:
1 10
2 20
3 30
22 220
42 420

Size of map: 5

Deleting key 2 -> 20
Size after deletion: 4

Value of key 3: 30
Value of key 2: -1

Is map empty? No

Complexity analysis for Insertion:

Time Complexity:

  • Best Case: O(1)
  • Worst Case: O(n). This happens when all elements have collided and we need to insert the last element by checking free space one by one.
  • Average Case: O(1) for good hash function, O(n) for bad hash function

Auxiliary Space: O(1)

Complexity analysis for Deletion:

Time Complexity:

  • Best Case: O(1)
  • Worst Case: O(n)
  • Average Case: O(1) for good hash function; O(n) for bad hash function

Auxiliary Space: O(1) 

Complexity analysis for Searching:

Time Complexity:

  • Best Case: O(1)
  • Worst Case: O(n)
  • Average Case: O(1) for good hash function; O(n) for bad hash function

Auxiliary Space: O(1) for search operation

Comment