Deleting an entry from a hash table using Open Addressing

  • Consider the initial hash table that uses Linear Probing:

     Empty hash table using Linear Probing:
    
                  0   1   2   3   4   5   6   7   8   9  10  11
                +---+---+---+---+---+---+---+---+---+---+---+---+
     bucket[] = |   |   |   |   |   |   |   |   |   |   |   |   |
                +---+---+---+---+---+---+---+---+---+---+---+---+
    
                     All entries contains null
    

  • How to remove the entry stored in bucket[i]:

        bucket[i] = null;    ???
    

    since the value null indicates an empty bucket...

  • Let's code the remove( ) algorithm first

    (And think about the consequences later...)

Naive version of the remove( ) algorithm of a hash table using linear probing

  • The initial version of the remove(k) algorithm using linear probing:

        public V remove(K k)  // Return the value associated with key k
        {
            int hashIdx = hashValue(k);
            int i = hashIdx;
    
            do
            {
                if ( bucket[i] == null ) // Is bucket empty ?
                {
                    return null;       // Key k is not in hash table
                }
                else if (bucket[i].key == k ) // Does bucket contains key k ?
                {
                    V retVal = bucket[i].value;
                    bucket[i] = AVAILABLE;    // Mark bucket as "available"
                    return retVal;            // Return value
                }
                i = (i + 1)%capacity;  // Check in next hash table bucket
    
            } while ( i != hashIdx ); // All entries searched !
    
            return null;  // No found
        }
    

     

Naive version of the remove( ) algorithm of a hash table using linear probing

  • Start the search for key y at the hash bucket:

        public V remove(K k)  // Return the value associated with key k
        {
            int hashIdx = hashValue(k);
            int i = hashIdx;
    
            do
            {
                if ( bucket[i] == null ) // Is bucket empty ?
                {
                    return null;       // Key k is not in hash table
                }
                else if (bucket[i].key == k ) // Does bucket contains key k ?
                {
                    V retVal = bucket[i].value;
                    bucket[i] = AVAILABLE;    // Mark bucket as "available"
                    return retVal;            // Return value
                }
                i = (i + 1)%capacity;  // Check in next hash table bucket
    
            } while ( i != hashIdx ); // All entries searched !
    
            return null;  // No found
        }
    

     

Naive version of the remove( ) algorithm of a hash table using linear probing

  • Search all the buckets i, i+1, i+2, ...:

        public V remove(K k)  // Return the value associated with key k
        {
            int hashIdx = hashValue(k);
            int i = hashIdx;
    
            do
            {
                if ( bucket[i] == null ) // Is bucket empty ?
                {
                    return null;       // Key k is not in hash table
                }
                else if (bucket[i].key == k ) // Does bucket contains key k ?
                {
                    V retVal = bucket[i].value;
                    bucket[i] = AVAILABLE;    // Mark bucket as "available"
                    return retVal;            // Return value
                }
                i = (i + 1)%capacity;  // Check in next hash table bucket
    
            } while ( i != hashIdx ); // All entries searched !
    
            return null;  // No found
        }
    

    Note: when i == hashIdx again, the search index i has wrap back to the start !

Naive version of the remove( ) algorithm of a hash table using linear probing

  • If we find an empty entry, then key k in not found in the hash table:

        public V remove(K k)  // Return the value associated with key k
        {
            int hashIdx = hashValue(k);
            int i = hashIdx;
    
            do
            {
                if ( bucket[i] == null ) // Is bucket empty ?
                {
                    return null;       // Key k is not in hash table
                }
                else if (bucket[i].key == k ) // Does bucket contains key k ?
                {
                    V retVal = bucket[i].value;
                    bucket[i] = AVAILABLE;    // Mark bucket as "available"
                    return retVal;            // Return value
                }
                i = (i + 1)%capacity;  // Check in next hash table bucket
    
            } while ( i != hashIdx ); // All entries searched !
    
            return null;  // No found
        }
    

    Return value null indicates the not found condition

Naive version of the remove( ) algorithm of a hash table using linear probing

  • If we find the entry containing key k, we replace it with null:

        public V remove(K k)  // Return the value associated with key k
        {
            int hashIdx = hashValue(k);
            int i = hashIdx;
    
            do
            {
                if ( bucket[i] == null ) // Is bucket empty ?
                {
                    return null;       // Key k is not in hash table
                }
                else if (bucket[i].key == k ) // Does bucket contains key k ?
                {
                    V retVal = bucket[i].value;
                    bucket[i] = null;         // Delete the entry 
                    return retVal;            // Return value
                }
                i = (i + 1)%capacity;  // Check in next hash table bucket
    
            } while ( i != hashIdx ); // All entries searched !
    
            return null;  // No found
        }
    

     

Naive version of the remove( ) algorithm of a hash table using linear probing

  • Finally, if we probed all entries and did not find the key k, we return null:

        public V remove(K k)  // Return the value associated with key k
        {
            int hashIdx = hashValue(k);
            int i = hashIdx;
    
            do
            {
                if ( bucket[i] == null ) // Is bucket empty ?
                {
                    return null;       // Key k is not in hash table
                }
                else if (bucket[i].key == k ) // Does bucket contains key k ?
                {
                    V retVal = bucket[i].value;
                    bucket[i] = null;         // Delete the entry 
                    return retVal;            // Return value
                }
                i = (i + 1)%capacity;  // Check in next hash table bucket
    
            } while ( i != hashIdx ); // All entries searched !
    
            return null;  // Not found
        }
    

    $64,000 question:   will remove(k) work correctly ???

Deleting an entry from a hash table using Open Addressing

  • Consider the insert example where we have inserted the keys R, S, V, P:

                            Hash value
        insert(R)                4
        insert(S)                6
        insert(V)                5
        insert(P)		     4 
    
    
    
                  0   1   2   3   4   5   6   7   8   9  10  11
                +---+---+---+---+---+---+---+---+---+---+---+---+
     bucket[] = |   |   |   |   | R | V | S | P |   |   |   |   |
                +---+---+---+---+---+---+---+---+---+---+---+---+
                                  ^           ^
                                  |           |
                               H(P)=4      (P, ..) inserted here
    
    

  • Consider the entry (P, ..) (where I omitted the data for brevity):

    • The hash value H(P) = 4

    • However, because the bucket 4 was used, the entry (P, ..) was inserted in bucket 7

Deleting an entry from a hash table using Open Addressing

  • Suppose we remove the entry (S, ..) by replacing the entry with null:

                            Hash value
        insert(R)                4
        insert(S)                6
        insert(V)                5
        insert(P)		     4 
    
        remove(S):
    
                  0   1   2   3   4   5   6   7   8   9  10  11
                +---+---+---+---+---+---+---+---+---+---+---+---+
     bucket[] = |   |   |   |   | R | V |   | P |   |   |   |   |
                +---+---+---+---+---+---+---+---+---+---+---+---+
                                  ^           ^
                                  |           |
                               H(P)=4      (P, ..) inserted here
    
    

  • $64,000 question:

    • Will the get( ) algorithm still work for get(P) ??

Review:   the get algorithm in Open Addressing with linear probing

  • The get(k) algorithm of Linear Probing:

       public V get(K k)
       {
           int hashIdx = H(k);  // Find the hash index for key k
           int i = hashIdx;
    
           do
           {
               if ( entry[i] == null ) // Is entry empty ?
    	   {
    	       return null;   // NOT found 
               }
               else if (entry[i].key == k )  // FOUND 
    	   {
    	       return bucket[i].value;
               }
    	   i = (i + 1)%M;  // Check in next hash table entry
    
           }  while ( i != hashIdx ) // All entries searched
    
           return null;  // NOT found 
       }
    

    Will the get( ) algorithm still work for get(P) ??

Problem with the get algorithm in Open Addressing with linear probing

  • The get(k) algorithm starts the search for key k at the hasg bucket:

       public V get(K k)
       {
           int hashIdx = H(k);  // Find the hash index for key k
           int i = hashIdx;   // Start search at hash bucket 
    
           do
           {
               if ( entry[i] == null ) // Is entry empty ?
    	   {
    	       return null;   // NOT found 
               }
               else if (entry[i].key == k )  // FOUND 
    	   {
    	       return bucket[i].value;
               }
    	   i = (i + 1)%M;  // Check in next hash table entry
    
           }  while ( i != hashIdx ) // All entries searched
    
           return null;  // NOT found 
       }
    

     

Problem with the get algorithm in Open Addressing with linear probing

  • When get(k) finds an empty bucket, it determines that key k is not found:

       public V get(K k)
       {
           int hashIdx = H(k);  // Find the hash index for key k
           int i = hashIdx;   // Start search at hash bucket 
    
           do
           {
               if ( entry[i] == null ) // Is entry empty ?
    	   {
    	       return null;   // NOT found 
               }
               else if (entry[i].key == k )  // FOUND 
    	   {
    	       return bucket[i].value;
               }
    	   i = (i + 1)%M;  // Check in next hash table entry
    
           }  while ( i != hashIdx ) // All entries searched
    
           return null;  // NOT found 
       }
    

     

Deleting an entry from a hash table using Open Addressing

  • Problem:   if we remove the entry (S, ..) replacing the entry with null:

                            Hash value
        insert(R)                4
        insert(S)                6
        insert(V)                5
        insert(P)		     4 
    
        remove(S):
    
                  0   1   2   3   4   5   6   7   8   9  10  11
                +---+---+---+---+---+---+---+---+---+---+---+---+
     bucket[] = |   |   |   |   | R | V |   | P |   |   |   |   |
                +---+---+---+---+---+---+---+---+---+---+---+---+
                                  ^       ^   ^
                                  |       |   |
                               H(P)=4     |  (P, ..) inserted here
                                          |
                        causes get( ) to conclude P is not found
    

  • The get( ) algorithm no longer work correctly !!!

The AVAILABLE entry

  • To solve the deletion problem, a hash table using Open Addressing uses a special entry called AVAILABLE:

        public Entry<K,V> AVAILABLE = new Entry<>(null, null);
    

  • How the AVAILABLE entry is used:

    1. When an existing entry in the hash table is removed:

      • The entry is replaced by the AVAILABLE entry

    2. When you are searching for key k then:

      • AVAILABLE must be treated as an empty bucket (i.e.: it does not contain any key

      • The rehash algorithm must continue with the next search location