符号表之四:符号表的链表实现和哈希表实现
2017-12-15 16:55
302 查看
介绍了符号表的组织形式有线性组织(重插入简洁性,轻索引性能),排序组织(插入操作耗时,重索引性能),哈希表映射(以空间换取时间)。那么如下便介绍了符号表的链表实现方式和哈希表实现方式,分别对应线性组织和哈希表映射两种方式,至于排序组织方式的实现其实只需要一个动态扩展数组便可以实现,较为简单不作讨论。网上关于符号表的实现代码有很多,没有必要重复造轮子,其中个人觉得实现最好的是erhuoxifu博主的两篇文章,代码质量很高,故而在他的代码基础上做一些讨论分析。
1. 符号表的List链表形式实现
首先来看下接口函数的设置 list.h
来看下具体的链表接口函数实现,我对原代码进行了一点更改,采用双向链表以加速删除这类操作的性能
list.cpp
2. 符号表的hash-table形式实现
首先来看下接口函数的设置 hash-table.h
hash-table.cpp
1. 符号表的List链表形式实现
首先来看下接口函数的设置 list.h
#ifndef _LIST_H_ #define _LIST_H_ /* *链表实现最大的优点便是动态插入的性能很好,故而显然每个符号表项(这里称为元素项)的具体实现方式 *采用链接节点的形式最好,这样既能实现动态扩展(不盲目扩展空间),又可以很好地实现链表关联 *所以这里分为两层结构,分别定义元素项的节点和管理链表的组织信息头结构体 */ typedef struct ListNode { char* key; void* value; struct ListNode* pre; struct ListNode* next; } ListNode; typedef struct List { struct ListNode* head_node; struct ListNode* tail_node; unsigned long uiNodeLength; } List; typedef struct List* pList; /* *如果是用C++编译器编译,那么接口函数为了可以被用在C语言中,声明采用C语言的函数修饰规则, **否则链接过程中可能会找不到正确的函数名 */ #ifdef __cplusplus extern "C" { #endif pList List_new( void ); /* *这里需要讨论的问题是,元素项节点结构体中存放着指向符号名key、元素值value的指针,那么在释放时 *符号名Key的空间释放我们是可以理解的,那么元素值value是否也需要在这里释放呢? *思考了一下,觉得还是不应该在List_free中释放具体的元素项的value指针,有两点考虑 *1.不符合“谁制造,谁负责”的原则,这样容易出现模块之间功能界限模糊 *2.元素项中存放具体元素值时,因为不知道元素值的类型,而采用通用指针void*,那么显然在不知道元素值类 *型的情况下,是无法正确释放该元素值所占用的空间的,虽然让用户自己负责自己的值空间的分配和释放确实容易 *出现忘记释放的情况,但是如果将该工作转移到symbol_list库中来实现,工作量和难度都会增加不少, *故而基于以上考虑,放弃在List_free和List_remove中对具体元素项的值空间的释放 */ void List_free( pList oList ); int List_getLength( pList oList ); /* *这里要讨论的是List_put如何遇到要存储元素已经存在,该如何面对,是更新,还是不更新? *我们知道在有些用户使用性友好的库中,这种插入操作有时是和replace混用的,但这要求库的设计者对 *库的使用场景足够熟悉,才能做出这种果断的融合操作的 *显然出于功能界限尽可能清晰的原则考虑,这里我还是认为不应该出现put插入和replace替换混用 */ int List_put( pList oList, const char* pcKey, const void* pvValue ); /* *和上面List_put同样的道理,既然是replace替换,所以就应该是要替换的元素已经存在在List中, *不应该增加:如果要替换的元素此前不存在,那么便将该元素项作为新插入项插入List中这种功能组合的设计 */ void* List_replace( pList oList, const char* pcKey, const void* pvValue ); int List_contains( pList oList, const char* pcKey ); /* *出于功能安全的角度考虑,库传出来给用户的值尽可能应该是传值、传bool这类的直接量,而不应该传出 *元素项指针,链表组织信息(如头结点地址)这类敏感的信息的指针 *所以这里的List_get应该完成的操作是根据给定的符号名来给出元素项具体值空间,前面又说道了List库 *是不对具体的元素值空间负责的,所以这里只能传出值空间首地址,让程序上层调用者来负责那些指针安全操作的 *内容,List库的原则应该是自己产生的指针信息绝对不外泄 */ void* List_get( pList oList, const char* pcKey ); /*参考上面关于List_free的描述*/ void* List_remove( pList oList, const char* pcKey ); /* *给List链表设计一个类似于lambda函数遍历操作的接口,结合了lambda函数+迭代器的原则, *功能目标是在List链表中将所有元素项调用传递的pfApply函数指针指向的函数调用一遍 */ void List_map( pList oList, void (*pfApply)(const char* pcKey, const void* pvValue, void* pvExtra), const void* pvExtra ); #ifdef __cplusplus } #endif #endif //end of _LIST_H_
来看下具体的链表接口函数实现,我对原代码进行了一点更改,采用双向链表以加速删除这类操作的性能
list.cpp
#include "list.h" //“”意味着优先在当前目录下搜索库 #include <stdio.h> //<>意味着按照#include环境变量设置的绝对路径进行搜索 #include <stdlib.h> #include <assert.h> #include <string.h> /* * Use calloc to allocate the memory, * because it will initialize all memory bits to zero. * calloc函数相比于malloc函数最大的不同便是初始化操作,前者带有分配空间全部清空的操作 */ static void* MyAlloc ( unsigned long size ) { void* tmp; tmp = ( void* ) calloc ( size, sizeof ( char ) ); assert( tmp ); return tmp; } pList List_new( void ) { return (pList)MyAlloc(sizeof(List)); } void List_free( pList oList ) { assert( oList ); ListNode* temp = oList->head_node; while ( temp ) { oList->head_node = oList->head_node->next; if ( temp->key ) free( temp->key ); //if ( temp->value ) //value的释放不应该由List内部来实现,应该遵循着谁制造,谁负责的逻辑 // free( temp->value ); free( temp ); temp = oList->head_node; } free( oList ); oList = NULL; } int List_getLength( pList oList ) { return oList->uiNodeLength; } /* *static修饰本函数仅限于本文件list.cpp内部使用,之所以加这一个函数是为了内部其他函数方便获取具体元素 *的指针信息,从而方便操作,但是该函数显然是不能向外部开放的 */ static ListNode* List_getKey( pList oList, const char* pcKey ) { assert( oList ); assert( pcKey ); if (strlen(pcKey) == 0) return NULL; if ( oList->uiNodeLength == 0) return NULL; ListNode* temp = oList->head_node; while (temp) { if( strcmp( pcKey, temp->key) == 0) return temp; temp = temp->next; } return NULL; } //插入元素项,如果元素项存在,那就意味着本次插入不成功,返回0,成功返回1 int List_put( pList oList, const char* pcKey, const void* pvValue ) { assert( oList ); assert( pcKey ); assert( pvValue); if ( strlen( pcKey) == 0) return 0; if ( List_getKey( oList, pcKey) ) return 0; else { ListNode* new_node = (ListNode*)MyAlloc( sizeof(ListNode) ); assert( new_node ); char* key = (char*)MyAlloc( strlen(pcKey) + 1); if (key == NULL) { free( new_node); return 0; } new_node->key = key; strcpy( new_node->key, pcKey ); new_node->value = (void*)pvValue; if (oList->uiNodeLength == 0) { oList->head_node = new_node; oList->tail_node = new_node; new_node->pre = NULL; new_node->next = NULL; oList->uiNodeLength = 1; return 1; } else { new_node->pre = oList->tail_node; new_node->next = NULL; oList->tail_node->next = new_node; oList->tail_node = new_node; oList->uiNodeLength += 1; return 1; } } } //根据给定的元素符号名查找该元素是否存在,如果存在返回1,否则返回0 int List_contains( pList oList, const char* pcKey ) { assert( oList ); assert( pcKey ); if ( List_getKey( oList, pcKey) ) return 1; else return 0; } //元素替换接口函数的实现,替换的前提是必须列表中存在这样的元素 void* List_replace( pList oList, const char* pcKey, const void* pvValue ) { assert( oList ); assert( pcKey ); ListNode* tempListNode = List_getKey( oList, pcKey ); if (tempListNode == NULL) return NULL; else { void* tempP = tempListNode->value; tempListNode->value = (void*) pvValue; return tempP; } } //根据具体元素的符号名查找元素项,但是显然不能返回该元素项的指针,而只能返回值空间的首地址, void* List_get( pList oList, const char* pcKey ) { assert( oList ); assert( pcKey ); if (strlen(pcKey) == 0) return NULL; else { ListNode* temp = List_getKey( oList, pcKey ); return temp ? temp->value : NULL; } } //删除指定符号名的元素项,并返回元素原值 void* List_remove( pList oList, const char* pcKey ) { assert( oList ); assert( pcKey ); if ( strlen(pcKey) == 0) return NULL; else { ListNode* temp = List_getKey( oList, pcKey ); void* tempValue = NULL; if (temp) { if ((temp != oList->tail_node) && (temp != oList->head_node)) { temp->pre->next = temp->next; temp->next->pre = temp->pre; } else if (temp == oList->head_node ) { if (oList->uiNodeLength == 1) { oList->head_node = NULL; oList->tail_node = NULL; } else { oList->head_node = temp->next; temp->next->pre = NULL; } } else //if (temp == oList->tail_node ) { if (oList->uiNodeLength == 1) { oList->head_node = NULL; oList->tail_node = NULL; } else { oList->tail_node = temp->pre; temp->pre->next = NULL; } } tempValue = temp->value; free(temp->key); //free(temp->value); free(temp); oList->uiNodeLength -= 1; } return tempValue; } } void List_map( pList oList, void (*pfApply)(const char* pcKey, const void* pvValue, void* pvExtra), const void* pvExtra ) { assert( oList ); assert( pvExtra ); assert( pfApply ); ListNode* temp = oList->head_node; while (temp) { assert( temp->key ); assert( temp->value ); pfApply( temp->key, temp->value, (void*)pvExtra); temp = temp->next; } return; }
2. 符号表的hash-table形式实现
首先来看下接口函数的设置 hash-table.h
#ifndef _HASH_TABLE_H_ #define _HASH_TABLE_H_ /*建立三级结构,分别是具体元素项、哈希单位置链、符号表,因为符号表机制采用的是诸侯鼎力的机制 *为了因对哈希冲突,本程序实现的是同一哈希key值处用链表串联来解决,而非传统的顺移方案 */ /*建立hash-table中的元项实现,因为每个元素项的哈希索引值可能存在冲突,所以应该在元素节点中保留 *插入冲突节点的可能性,这便是引入struct ListNode* next的原因 */ typedef struct ListNode { char* key; void* value; struct ListNode* next; }ListNode; /*声明该链的组织信息*/ typedef struct ListAssociation { struct ListNode* head_node; struct ListNode* tail_node; unsigned long uiNodeLength; //指明该链长度 }ListAssociation; typedef struct HashTable { struct ListAssociation** bucketTable;//子表的索引入口 unsigned long uiBindingsCount; //保存该hash-table所有有效子表的数目 unsigned long uiBucketCount; //保存当前哈希表内含的子表数目的上限 } HashTable; typedef struct HashTable* HashTable_t; #ifdef __cplusplus extern "C" { #endif /*初始化哈希表,根据给定的容量设置BucketCount,初始化BucketCount个listAssocation*指针信息*/ HashTable_t HashTable_new( void ); void HashTable_free( HashTable_t oHashTable ); int HashTable_getLength( HashTable_t oHashTable ); /* *往指定哈希表插入新元素,和讨论符号表的List实现时一样,既然是插入新元素,那么如果不是新元素 *那么显然插入新元素是不存在,即插入新元素和更改元素的功能严格分离 */ int HashTable_put ( HashTable_t oHashTable, const char* pcKey, const void* pvValue); void* HashTable_get( HashTable_t oHashTable, const char* pcKey ); /*将哈希表原有的元素项的值替换成新值pvValue,并返回旧值,如果该元素项不存在,则返回NULL*/ void* HashTable_replace( HashTable_t oHashTable, const char* pcKey, const void* pvValue); /*在哈希表中,给定元素的符号名,删除该指定元素项*/ void* HashTable_remove( HashTable_t oHashTable, cosnt char* pcKey); void HashTable_map( HashTable_t oHashTable, void (*pfApply)( const char* pcKey, const void* pvValue, void* pvExtra), const void* pvExtra );
hash-table.cpp
#include "hash-table.h" #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <string.h> #define ARRAY_SIZE 3 static const unsigned long kBucketCount[ARRAY_SIZE] = {1024, 2048, 666666}; static int giBucketCountIndex = 0; static void* MyAlloc( unsigned long size ); /* *给定一个符号表组名称,和当前要查找的元素符号名key --pcKey,因为同样的符号名可能存在哈希冲突,故而应该 *返回的是一个单向链表的表头或链表信息节点 */ static ListAssociation* HashTable_getListAssociation ( HashTable_t oHashTable, const char* pcKey ); /*给定一个冲突链条,在其中查找具体的元素节点*/ static ListNode* ListAssociation_getListNode ( const ListAssociation* pListAssociation, const char* pcKey ); /*在哈希表中直接查找到具体元素项的首地址,注意static修饰符,该函数是该文件的内部函数,纯粹是为了方便 *其他函数的实现,对外部并不可见,之所以提到最前面给出函数声明,是因为该库要兼容C,所以才会有这些操作 */ static ListNode* HashTable_getListNode( HashTable_t oHashTable, const char* pcKey ); /*非覆盖版插入操作,即插入和更新绝对不混用*/ static int ListAssociation_put( ListAssociation* pListAssociation, const char* pcKey, const void* pvValue ); /*hash-table扩展操作,如果当前哈希表容量不足,则由1024->2048->666666递增,递增成功,则返回1,否则返回0*/ static int Rehash( HashTable_t oHashTable ); static int ListAssociation_put_help_rehash( ListAssociation* pListAssociation, ListNode* pListNode ); /*获取当前哈希表的容量所处级别*/ static int GetBucketSizeIndex( unsigned long uiBucketCounts ); /*很简单的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]; //初始将hash_table初始化为1024个节点 pListAssociation = (ListAssociation**) MyAlloc(temp->uiBucketCount * sizeof( ListAssociation* ) ); if (pListAssociation == NULL) { free(temp); return NULL; } temp->bucketTable = pListAssociation; } return temp; } void HashTable_free( HashTable_t oHashTable ) { assert( oHashTable ); unsigned long uiBucketCount = oHashTable->uiBucketCount; //遍历删除子表的内容 struct ListAssociation* pListAssociation = NULL; for (int i = 0; i<uiBucketCount; i++ ) { 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) { free( temp->value ); free( temp->key ); } free(temp); } free( pListAssociation); 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 ); //确保当前哈希表的子表数目不为0 if (0 == strlen( pcKey) ) return 0; if (oHashTable->uiBucketCount < kBucketCount[ARRAY_SIZE-1] ) { if (oHashTable->uiBindingsCount >= oHashTable->uiBucketCount ) { if( Rehash(ohashTable) == 0) return 0; } } ListAssociation* pListAssociation = HashTable_getListAssociation( oHashTable, pcKey ); if (NULL == pListAssociation ) { pListAssociation = ( ListAssociation* ) MyAlloc( sizeof(ListAssociation) ); if (pListAssociation == NULL ) return 0; oHashTable->bucketTable[HashTable_hash( pcKey, oHashTable->uiBucketCount)] = pListAssociation; } 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; else 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; } //对哈希表中所有元素进行遍历操作,操作函数为pfApply指定的函数指针 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; int i = 0; if ( HashTable_getLength( oHashTable) == 0) return; for ( i = 0; i< uiBucketCount; i++) { ListAssociation* pListAssociation = oHashTable->bucketTable[i]; if (pListAssociation == NULL) 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; } //将哈希表原有的元素项的值替换成新值pvValue,并返回旧值,如果该元素项不存在,则返回NULL 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, cosnt char* pcKey) { assert( oHashTable ); assert( pcKey ); ListAssociation* pListAssociation = HashTable_getListAssociation( oHashTable, pcKey); if (pListAssociation == NULL) return NULL; void* value = NULL; ListNode* temp = pListAssociation->head_node; ListNode* pre_node = NULL; //如果哈希后得到位置处没有有效信息,则可以直接返回 if (temp = NULL) return NULL; //如果哈希后位置处有信息,则需要遍历该处的具体链表,查找到匹配的”符号名“ //1. 链表首项就是要查找的元素项,则需要额外处理,因为涉及到pListAssociation->head_node等组织信息的更新 if( strcmp(pcKey, temp->key) == 0) { value = temp->value; pListAssociation->head_node = temp->next; free(temp->value); 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 (temp == NULL) return NULL; if ( strcmp(pcKey, temp->key) == 0 ) { pre_node->next = temp->next; //链条串起来不能断 if ( temp == pListAssociation->tail_node ) pListAssociation->tail_node = pre_node; value = temp->value; free( temp->key ); free( temp->value); free( temp ); pListAssociation->uiNodeLength = pListAssociation->uiNodeLength - 1; oHashTable->uiBindingsCount = oHashTable->uiBindingsCount - 1; return value; } } return NULL; } static void* MyAlloc( unsigned long size ) { void* temp = (void*) malloc( size*sizeof(char) ); assert(temp); return temp; } //给定元素项的“符号名”,返回哈希后该元素项在哈希表中下表位置 static ListAssociation* HashTable_getListAssociation( HashTable_t oHashTable, const char* pcKey) { assert( oHashTable); assert( pcKey); if ( strlen(pcKey) == 0) return NULL; int iHash_key = -1; iHash_key = HashTable_hash( pcKey, oHashTable->uiBucketCount ); assert( iHash_key >= 0); return oHashTable->bucketTable[iHash_key]; } //应对哈希冲突,如果同样的哈希值处存在多个元素项,则采用链表方式组织,故而针对具体的符号名需要二次操作 //1. 将符号名哈希后得到下标位置; 2.在下标位置上遍历链表进一步找到匹配的符号名项 static ListNode* ListAssociation_getListNode( const ListAssociation* pListAssociation, const char* pcKey) { assert( pListAssociation ); assert( pcKey ); if (strlen(pcKey) == 0) return NULL; ListNode* pListNode = pListAssociation->head_node; while ( pListNode ) { if ( strcmp( pcKey, pListNode->key ) == 0 ) return pListNode; pListNode = pListNode->next; } return NULL; } //在具体哈希值链条上插入元素,如果该元素原先存在,则直接返回0;如果不存在则新建项,并插入链表中,并返回1 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) ); assert(new_node); char* key = (char*)MyAlloc( strlen( pcKey) + 1); if (key == NULL) { free(new_node); return 0; } new_node->key = key; strcpy( new_node->key, pcKey ); new_node->value = (void*)pvValue; if ( pListAssociation->uiNodeLength == 0) { pListAssociation->head_node = new_node; pListAssociation->tail_node = new_node; pListAssociation->uiNodeLength = 1; return 1; } else { 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 (strlen(pcKey) == 0) return NULL; ListAssociation* pListAssociation = NULL; if (HashTable_getLength( oHashTable) == 0) return NULL; pListAssociation = HashTable_getListAssociation( oHashTable, pcKey); if (pListAssociation == NULL) 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); if ((ARRAY_SIZE-1) == giBucketCountIndex ) return 1; giBucketCountIndex++; unsigned long uiBucketCounts = kBucketCount[giBucketCountIndex]; struct ListAssociation** pNewListAssociation = NULL; pNewListAssociation = ( ListAssocaition**)MyAlloc( uiBucketCounts * sizeof( ListAssocaition*) ); if (pNewListAssociation == NULL) return 0; //将原先哈希表中的内容进行整体搬迁,由于并无时间序上的要求,故而搬迁时对于不同节点的先入先出顺序并无特殊要求 unsigned long uiOldBucketCount = oHashTable->uiBucketCount; unsigned long i = 0; for( ; i < uiOldBucketCount; i++ ) { struct ListAssociation* pOldListAssociation = NULL; pOldListAssociation = oHashTable->bucketTable[i]; if ( pOldListAssociation == NULL ) continue; ListNode* pTempListNode = pOldListAssociation->head_node; while ( pTempListNode ) { int iHash_key = -1; iHash_key = HashTable_hash( pTempListNode->key, uiBucketCounts ); assert( iHash_key >= 0 ); ListAssocaition* pListAssociation = pNewListAssociation[iHash_key]; if ( pListAssociation == NULL) { pListAssociation = (ListAssocaition*)MyAlloc( sizeof(ListAssocaition) ); if (pListAssociation == NULL) return 0; pNewListAssociation[iHash_key] = pListAssociation; } pOldListAssociation->head_node = pOldListAssociation->head_node->next; if (ListAssociation_put_help_rehash( pListAssociation, pTempListNode ) == 0) return 0; pTempListNode = pOldListAssociation->head_node; } free( pOldListAssociation ); pOldListAssociation = NULL; } free( oHashTable->bucketTable ); //将哈希表的新的组织信息更新 oHashTable->bucketTable = pNewListAssociation; oHashTable->uiBucketCount = uiBucketCounts; //oHashTable->uiBindingsCount代表当前有效链表数目,不变 return 1; } //该函数时配合rehash函数的,出于的目的主要是重复利用原有的元素项,而不需要重新分配 static int ListAssociation_put_help_rehash( ListAssocaition* pListAssociation, ListNode* pListNode ) { assert( pListAssociation ); assert( pListNode ); assert( pListAssociation->uiNodeLength >= 0 ); //如果该链表已经存在该同符号名元素项,则返回 if ( ListAssociation_getListNode( pListAssociation, pListNode->key) ) return 0; else { //如果链表是空,则 if (pListAssociation->uiNodeLength == 0) { pListAssociation->head_node = pListNode; pListAssociation->tail_node = pListNode; pListAssociation->tail_node->next = NULL; pListAssociation->uiNodeLength = 1; return 1; } else { pListAssociation->tail_node->next = pListNode; pListAssociation->tail_node = pListNode; pListNode->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; }
相关文章推荐
- 哈希表的基本运算(链表实现)
- 简单符号表的实现(链表和数组)
- java实现 数据结构:链表、 栈、 队列、优先级队列、哈希表
- 用两个哈希表加链表实现malloc
- [Leetcode] LRU Cache. 哈希表+双向链表之实现
- 无序链表实现符号表
- 利用数组和链表实现简单的哈希表
- java实现堆栈、哈希表、链表
- 用哈希表加链表实现动态malloc
- 无序符号表(链表实现,JAVA,算法(四))
- java实现 数据结构:链表、 栈、 队列、优先级队列、哈希表
- java实现单项链表以及如何检测回环
- 循环链表及双向链表的c语言实现
- 循环链表的实现
- 单向链表简单实现
- 第十五周项目1—哈希表及其运算实现
- 数据结构:线性表的链式存储(单向链表)--Java实现
- 定时链表处理 程序 采用 链表结构 同时运行多个定时器 仿PLC定时器结构实现
- Java 实现单向链表
- 哈希表在Java类库中的实现——HashSet