符号表之Hash table 实现

来源:互联网 发布:淘宝卖写真集违规吗 编辑:程序博客网 时间:2024/06/07 04:57

如有错误请指正

接口定义请参考 点击打开链接,只有接口名字不一样,所里这里不再列出了。


接口实现

#include "hash.h"#include <stdio.h>#include <stdlib.h>#include <assert.h>#include <string.h>#define ARRAY_SIZE 3// Store the bucket counts of hash tablestatic const unsigned long kBucketCount[ARRAY_SIZE] = \{1024, 2048, 666666};// Hold current Bucket sizestatic int giBucketCountIndex = 0;/* ListNode to identify the data unit under processing */typedef struct ListNode{    char*        key;     // Current node key    void*        value;  // Pointer to the value which binding to the key    struct ListNode* next; // Next node} ListNode;/** Association */typedef struct ListAssociation{    struct ListNode*      head_node;    struct ListNode*      tail_node;    unsigned long         uiNodeLength; // The length of linked list} ListAssociation;/* HashTable to collect the hash table data  */typedef struct HashTable{    struct ListAssociation**  bucketTable;    unsigned long      uiBindingsCount; // Hold bindings size    unsigned long      uiBucketCount;   // Hold Bucket size} HashTable;typedef struct HashTable* HashTable_t;/* Local help function* Use calloc to allocate the memory,* because it will initialize all memory bits to zero.*/static void* MyAlloc ( unsigned long size );/***Local function, if find out the pcKey return the ListAssociation*,*other return NULL*/static ListAssociation* HashTable_getListAssociation(    HashTable_t oHashTable,    const char* pcKey );/***Local function, if find out the pcKey return the ListNode*,*other return NULL*/static ListNode* ListAssociation_getListNode(    const ListAssociation* pListAssociation,    const char* pcKey );/***Local function.*If a pcKey isn’t already in the ListAssociation pointed to by *pListAssociation,inserts it into the ListAssociation and returns 1.*If not enough memory is available or pcKey already is in the *ListAssociation, the function will leave ListAssociation *unchanged and return 0.*/static int ListAssociation_put( ListAssociation* pListAssociation,                                const char* pcKey,                                const void* pvValue );/***Local function, if find out the pcKey return the ListNode*,*other return NULL*/static  ListNode* HashTable_getListNode( HashTable_t oHashTable,                                        const char* pcKey );/***Local help function,Refresh the hash table.*For the rehash function, this is the array of bucket counts:  *1024, 2048, 666666. Initially, *the bucket count should be set to the first size (1024). When*HashTable_put detects that the total number of bindings exceeds the *current bucket count,1024, a rehash function should increase the *bucket count to 2048. Then as number of bindings exceeds 2048, the*bucket count should be 666666. If the binding count goes *over 666666, the bucket count should not be increased again. *If successful return 1, otherwise return 0*/static int Rehash( HashTable_t oHashTable );/*** For help Rehash().*/static int ListAssociation_put_help_rehash( ListAssociation* pListAssociation,                                            ListNode* pListNode );/*** Update giBucketCountIndex.* In some cases(example cycle test) the  giBucketCountIndex may be wrong,* so need update it to the real index.*/static int GetBucketSizeIndex( unsigned long uiBucketCounts );// HashTable_hash int HashTable_hash( const char* pcKey, int iBucketCount ){    int i;    unsigned int uiHash = 0U;    assert( pcKey != NULL );    for ( i = 0; pcKey[i] != '\0'; i++ )    {        uiHash = uiHash * 66666                 + ( unsigned int )pcKey[i];    }    return ( int )( uiHash % ( unsigned int ) iBucketCount );}HashTable_t HashTable_new( void ){    HashTable_t temp = ( HashTable_t ) MyAlloc ( sizeof ( HashTable ) );    if ( temp )    {        struct ListAssociation** pListAssociation = NULL;        temp->uiBucketCount = kBucketCount[0];// The default Bucket size        pListAssociation = ( ListAssociation** )\                           MyAlloc( temp->uiBucketCount * sizeof( ListAssociation* ) );        if ( NULL == pListAssociation )        {            free( temp );            return NULL;        }        temp->bucketTable = pListAssociation;    }    return temp;}void HashTable_free( HashTable_t oHashTable ){    assert ( oHashTable );    unsigned long uiBucketCount = oHashTable->uiBucketCount;    unsigned i = 0;    for ( i = 0; i < uiBucketCount; ++i )    {        struct ListAssociation* pListAssociation = NULL;        pListAssociation = oHashTable->bucketTable[i];        if ( NULL == pListAssociation )        {            continue;        }        ListNode* temp = pListAssociation->head_node;        while ( temp )        {            pListAssociation->head_node = pListAssociation->head_node->next;            if ( temp->key )// Release key            {                free ( temp->key );            }            free ( temp ); // Release ListNode            temp =  pListAssociation->head_node;        }        free( pListAssociation );// Release ListAssociation        pListAssociation = NULL;    }    free( oHashTable->bucketTable );    free ( oHashTable );    oHashTable = NULL;}int HashTable_getLength( HashTable_t oHashTable ){    return oHashTable->uiBindingsCount;}int HashTable_put( HashTable_t oHashTable, const char* pcKey, const void* pvValue ){    assert ( oHashTable );    assert ( pcKey );    assert ( pvValue );    assert  ( oHashTable->uiBucketCount );    if ( 0 == strlen( pcKey ) )    {        return 0;    }    // Check if the Bucket counts < 666666    if ( oHashTable->uiBucketCount < kBucketCount[ARRAY_SIZE - 1] )    {        // If bindings counts > Bucket counts,refresh the hash table,        if ( oHashTable->uiBindingsCount >= oHashTable->uiBucketCount )        {            // Refresh the hash table            if ( 0 == Rehash( oHashTable ) )            {                return 0;            }        }    }    ListAssociation* pListAssociation = HashTable_getListAssociation( oHashTable, pcKey );    if ( NULL == pListAssociation ) // There is no ListAssociation* in table    {        pListAssociation = ( ListAssociation* )MyAlloc ( sizeof( ListAssociation ) );        if ( NULL == pListAssociation )        {            return 0;        }        // Put pListAssociation into table        oHashTable->bucketTable[HashTable_hash( pcKey, oHashTable->uiBucketCount )] = pListAssociation;    }    // Insert the bindings into ListAssociation    if ( ListAssociation_put( pListAssociation, pcKey, pvValue ) )    {        oHashTable->uiBindingsCount = oHashTable->uiBindingsCount + 1;        return 1;    }    return 0;}int HashTable_contains( HashTable_t oHashTable, const char* pcKey ){    assert ( oHashTable );    assert ( pcKey );    if ( HashTable_getListNode( oHashTable, pcKey ) )    {        return 1;    }    return 0;}void* HashTable_get( HashTable_t oHashTable, const char* pcKey ){    assert ( oHashTable );    assert ( pcKey );    ListNode* pListNode = HashTable_getListNode( oHashTable, pcKey );    if ( pListNode )    {        return pListNode->value;    }    return NULL;}void HashTable_map( HashTable_t oHashTable,                   void ( *pfApply )( const char* pcKey, const void* pvValue, void* pvExtra ),                   const void* pvExtra ){    assert ( oHashTable );    assert ( pfApply );    assert ( pvExtra );    unsigned long uiBucketCount = oHashTable->uiBucketCount;    unsigned i = 0;    // The table is empty, return    if ( 0 == HashTable_getLength( oHashTable ) )    {        return;    }    for ( i = 0; i < uiBucketCount; ++i )    {        ListAssociation* pListAssociation = oHashTable->bucketTable[i];        if ( NULL == pListAssociation )        {            continue;        }        ListNode* pListNode = pListAssociation->head_node;        while ( pListNode )        {            assert ( pListNode->key );            assert ( pListNode->value );            pfApply( pListNode->key, pListNode->value, ( void* )pvExtra );            pListNode =  pListNode->next;        }    }    return;}void* HashTable_replace( HashTable_t oHashTable, const char* pcKey, const void* pvValue ){    assert ( oHashTable );    assert ( pcKey );    void* value = NULL;    ListNode* pListNode = HashTable_getListNode( oHashTable, pcKey );    if ( pListNode )    {        value = pListNode->value;        pListNode->value = ( void* )pvValue;    }    return value;}void* HashTable_remove( HashTable_t oHashTable, const char* pcKey ){    assert ( oHashTable );    assert ( pcKey );    ListAssociation* pListAssociation = HashTable_getListAssociation( oHashTable, pcKey );    if ( NULL == pListAssociation )    {        return NULL;    }    void* value = NULL;    ListNode* temp = pListAssociation->head_node;    ListNode* pre_node = NULL;    /*    *The key-value maybe has been removed    *or has not inserted successfully    */    if ( NULL == temp )    {        return NULL;    }    if ( 0 == strcmp ( pcKey, temp->key ) )   // Head node is the node which need to be removed    {        value = temp->value;        pListAssociation->head_node = temp->next;        free ( temp->key );        free ( temp );        pListAssociation->uiNodeLength = pListAssociation->uiNodeLength - 1;        oHashTable->uiBindingsCount =       oHashTable->uiBindingsCount - 1;        return value;    }    while ( 1 )    {        pre_node = temp;        temp = temp->next;        if ( NULL == temp )        {            return NULL;        }        if ( 0 == strcmp ( pcKey, temp->key ) )   // Find it        {            pre_node->next = temp->next;            value = temp->value;            // Do not forget to release the memory            free ( temp->key );            free ( temp );            // Update the counts            pListAssociation->uiNodeLength = pListAssociation->uiNodeLength - 1;            oHashTable->uiBindingsCount =  oHashTable->uiBindingsCount - 1;            return value;        }    }    return NULL;}static void* MyAlloc ( unsigned long size ){    void* tmp;    tmp = ( void* ) calloc ( size, sizeof ( char ) );    assert( tmp );    return tmp;}static  ListAssociation* HashTable_getListAssociation( HashTable_t oHashTable,                                                      const char* pcKey ){    assert ( oHashTable );    assert ( pcKey );    if ( 0 == strlen( pcKey ) )    {        return NULL;    }    int iHash_key = -1;    iHash_key = HashTable_hash( pcKey, oHashTable->uiBucketCount );    assert( iHash_key >= 0 );    return oHashTable->bucketTable[iHash_key];}static  ListNode* ListAssociation_getListNode( const ListAssociation* pListAssociation,                                               const char* pcKey ){    assert ( pListAssociation );    assert ( pcKey );    if ( 0 == strlen( pcKey ) )    {        return NULL;    }    ListNode* pListNode = pListAssociation->head_node;    while ( pListNode )    {        if ( 0 == strcmp ( pcKey, pListNode->key ) )        {            return pListNode;        }        pListNode =  pListNode->next;    }    return NULL;}static int ListAssociation_put( ListAssociation* pListAssociation,                                const char* pcKey,                                const void* pvValue ){    assert ( pListAssociation );    assert ( pcKey );    assert ( pvValue );    if ( ListAssociation_getListNode( pListAssociation, pcKey ) )    {        return 0;    }    else    {        ListNode* new_node = ( ListNode* )MyAlloc ( sizeof( ListNode ) );        if ( NULL == new_node )        {            return 0;        }        char* key = ( char* ) MyAlloc ( strlen ( pcKey ) + 1 );        if ( NULL == key )        {            free( new_node );            return 0;        }        new_node->key = key;        strcpy ( new_node->key, pcKey );        new_node->value = ( void* )pvValue; //??        if ( 0 == pListAssociation->uiNodeLength )   // The list is empty        {            pListAssociation->head_node = new_node;            pListAssociation->tail_node = new_node;            pListAssociation->uiNodeLength = 1;            return 1;        }        if ( 1 == pListAssociation->uiNodeLength )   // Only one key-value in list        {            pListAssociation->head_node->next = new_node;            pListAssociation->tail_node = new_node;            pListAssociation->uiNodeLength = 2;            return 1;        }        else     // More than one key-value in list        {            pListAssociation->tail_node->next = new_node;            pListAssociation->tail_node = new_node;            pListAssociation->uiNodeLength += 1;            return 1;        }    }}static  ListNode* HashTable_getListNode( HashTable_t oHashTable, const char* pcKey ){    assert ( oHashTable );    assert ( pcKey );    if ( 0 == strlen( pcKey ) )    {        return NULL;    }    ListAssociation* pListAssociation = NULL;    if ( 0 == HashTable_getLength( oHashTable ) )    {        return NULL;    }    pListAssociation = HashTable_getListAssociation( oHashTable, pcKey );    if ( NULL == pListAssociation )    {        return NULL;    }    return ListAssociation_getListNode( pListAssociation, pcKey );}static int Rehash( HashTable_t oHashTable ){    assert( oHashTable );    assert( oHashTable->uiBindingsCount >= oHashTable->uiBucketCount );    giBucketCountIndex = GetBucketSizeIndex( oHashTable->uiBucketCount );    assert( giBucketCountIndex >= 0 );    unsigned long uiBucketCounts = 0;    if ( ( ARRAY_SIZE - 1 ) == giBucketCountIndex )    {        return 1;    }    ++giBucketCountIndex;    uiBucketCounts = kBucketCount[giBucketCountIndex];    // Create a new ListAssociation** base on uiBucketCounts    struct ListAssociation** pNewListAssociation = NULL;    pNewListAssociation = ( ListAssociation** )MyAlloc( uiBucketCounts * sizeof( ListAssociation* ) );    if ( NULL == pNewListAssociation )    {        return 0;    }    // Update the old ListAssociation** to new ListAssociation**    {        unsigned long uiBucketCount = oHashTable->uiBucketCount;        unsigned long i = 0;        for ( i = 0; i < uiBucketCount; ++i )        {            struct ListAssociation* pOldListAssociation = NULL;            pOldListAssociation = oHashTable->bucketTable[i];            if ( NULL == pOldListAssociation )            {                continue;            }            ListNode* pTempListNode = pOldListAssociation->head_node;            // Iterate current ListNode and update the bindings to new table            while ( pTempListNode )            {                int iHash_key = -1;                iHash_key = HashTable_hash( pTempListNode->key, uiBucketCounts );                assert( iHash_key >= 0 );                ListAssociation* pListAssociation = pNewListAssociation[iHash_key];                if ( NULL == pListAssociation ) // There is no ListAssociation* in table                {                    pListAssociation = ( ListAssociation* )MyAlloc ( sizeof( ListAssociation ) );                    if ( NULL == pListAssociation )                    {                        return 0;                    }                    // Put ListAssociation* into new table                    pNewListAssociation[iHash_key] = pListAssociation;                }                pOldListAssociation->head_node = pOldListAssociation->head_node->next;                if ( 0 == ListAssociation_put_help_rehash( pListAssociation, pTempListNode ) )                {                    return 0;                }                pTempListNode =  pOldListAssociation->head_node;            }            // Do not forget to release memory            free( pOldListAssociation );            pOldListAssociation = NULL;        }    }    free( oHashTable->bucketTable );    // Update for the new BucketSize    oHashTable->bucketTable = pNewListAssociation;    oHashTable->uiBucketCount = uiBucketCounts;    return 1;}static int ListAssociation_put_help_rehash( ListAssociation* pListAssociation,                                            ListNode* pListNode ){    assert ( pListAssociation );    assert ( pListNode );    if ( ListAssociation_getListNode( pListAssociation, pListNode->key ) )    {        return 0;    }    else    {        if ( 0 == pListAssociation->uiNodeLength )   // The list is empty        {            pListAssociation->head_node = pListNode;            pListAssociation->tail_node = pListNode;            pListAssociation->tail_node->next = NULL;            pListAssociation->uiNodeLength = 1;            return 1;        }        // Only one key-value in list        if ( 1 == pListAssociation->uiNodeLength )        {            pListAssociation->head_node->next = pListNode;            pListAssociation->tail_node = pListNode;            pListAssociation->tail_node->next = NULL;            pListAssociation->uiNodeLength = 2;            return 1;        }        else     // More than one key-value in list        {            pListAssociation->tail_node->next = pListNode;            pListAssociation->tail_node = pListNode;            pListAssociation->tail_node->next = NULL;            pListAssociation->uiNodeLength += 1;            return 1;        }    }}static int GetBucketSizeIndex( unsigned long uiBucketCounts ){    int i = 0;    for ( i = 0; i < ARRAY_SIZE; ++i )    {        if ( uiBucketCounts == kBucketCount[i] )        {            giBucketCountIndex = i;            return giBucketCountIndex;        }    }    return -1;}












0 0
原创粉丝点击