您的位置:首页 > 其它

符号表之四:符号表的链表实现和哈希表实现

2017-12-15 16:55 302 查看
介绍了符号表的组织形式有线性组织(重插入简洁性,轻索引性能),排序组织(插入操作耗时,重索引性能),哈希表映射(以空间换取时间)。那么如下便介绍了符号表的链表实现方式和哈希表实现方式,分别对应线性组织和哈希表映射两种方式,至于排序组织方式的实现其实只需要一个动态扩展数组便可以实现,较为简单不作讨论。网上关于符号表的实现代码有很多,没有必要重复造轮子,其中个人觉得实现最好的是erhuoxifu博主的两篇文章,代码质量很高,故而在他的代码基础上做一些讨论分析。

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息