roger roger - 9 days ago 6
C Question

how to search using double hash in c

I have a server to receive request from multiple client. I have done this with threads. I want to insert some user name and password to hash table. For that I am using double hash method. It was inserted successfully. But I want to know when user enter a user name, I need to search on hash table whether this username already present. But I can't do it now. I know the concept like using hashing. Get the index using hashfunction1 through username and use double hash like this. But how can I write that code ?

My code:

int HashFunc1 (char *key,int size)
{
int i = 0,value = 0;

for(i = 0 ; key[i] != '\0'; i++)
{
value += ( key[i] + ( i + 1 ) );
}
return value % size;
}

int HashFunc2 (char *key,int size)
{
int i = 0,value = 0;

for(i = 0; key[i] != '\0'; i++)
{
value += ( key[i] + ( i + 1 ) );
}

return (value * size - 1) % size;
}

int Findindex(char *key,struct HashTable **htable)
{

int hashVal = 0,
stepSize = 0;

hashVal = HashFunc1(key, (*htable)->size);
stepSize= HashFunc2(key, (*htable)->size);

/*to avoid collisions)*/
while ( (*htable)->table[hashVal].username != NULL)
{
/*double hahsing process*/
hashVal = hashVal + stepSize;
hashVal = hashVal % (*htable)->size;
}

return hashVal;

}

int insert_to_hashtable(char *key,char *password,struct HashTable **htable)
{
int pos = 0;

/*find the index to insert new user datas*/
pos = Findindex(key,htable);

//code to insert to coresponding data if this empty
}


How can I write code to search a username is already present using double hashing from hash table in C? I think traverse whole hash table is not good practice ..is it?

Answer

Your hashtable is of a fixed size S, so you can enter at most S elements.

The idea of the double hash with hash codes H1 and H2 is: If there is already an entry at position H1, traverse the hash width the stride H2. The size S is a prime. That means that with any stride H2 < S except H2 = 0, you will eventually visit all entries before coming full circle.

Of course, if you find an empty slot, you take it. In a sparsely populated hash, you usually have to go only a few steps from the original value to find an emty slot.

The more populated your hash gets, the less efficient the key search will be. One solution is to keep track of the number of elements and resize the hash to a bigger size when, say, more than 75% of entries are occupied. The new size must, of course, also be prime.

Also note these problems in your code: You might generate a hash value of 0 for the step size and if your hash table is full, your search for an empty slot will loop infinitely. It is also not necessary to pass the hash table by reference, because you never change the pointer itself, just its struct members. You can even make both key and htable const.

So:

int Findindex(const char *key, const struct HashTable *htable)
{    
    int hashVal, stepSize, startVal;

    hashVal = HashFunc1(key, htable->size);
    if (htable->table[hashVal].username == NULL) return hashVal;

    startVal = hashVal;
    stepSize = HashFunc2(key, (*htable)->size - 1) + 1;

    do  {
        hashVal = (hashVal + stepSize) % htable->size;
        if (hashVal == startVal) return -1;
    } while (htable->table[hashVal].username);

    return hashVal;
}

This code returns a special value -1 to indicate that there aren't any empty slots in the hash table.

If you want to look up a username, you use the same strategy. Here, you must additionally compare the key for each node, because different keys may share the same hash code. If you find an empty slot, the entry is not in the table.

This function returns a pointer to the user data (whose type I've named struct data; you don't show thze definition of the hash table struct) associated with the key or NULL if the user can't be found:

struct data *FindKey(const char *key, const struct HashTable *htable)
{    
    int hashVal, stepSize, startVal;

    hashVal = HashFunc1(key, htable->size);
    if (htable->table[hashVal].username == NULL) return NULL;
    if (strcmp(htable->table[hashval].username, key) == 0) {
        return &htable->table[hashVal];
    }

    startVal = hashVal;
    stepSize = HashFunc2(key, (*htable)->size - 1) + 1;

    for(;;)  {
        hashVal = (hashVal + stepSize) % htable->size;
        if (hashVal == startVal) return NULL;
        if (htable->table[hashVal].username == NULL) return NULL;
        if (strcmp(htable->table[hashval].username, key) == 0) {
            return &htable->table[hashVal];
        }
    }

    return NULL;
}

Caveat: I haven't tested this code, but I hope that you understand the basic working.

Comments