typedef int KeyType; typedef int ValueType; typedef struct HashNode { KeyType _key; ValueType _value; struct HashNode* _next; }HashNode; typedef struct HashTable { HashNode** _tables; size_t _size; size_t _N; }HashTable; size_t HashFunc(KeyType key, size_t N) { return key%N; }next指针。用来寻找下一个元素。
HashNode** _tables;
HashNode* BuyHashNode(KeyType key, ValueType value) { HashNode *NewNode = NULL; NewNode = (HashNode*)malloc(sizeof(HashNode)); NewNode->_key = key; NewNode->_value = value; NewNode->_next = NULL; return NewNode; }next指针的初始化。
void HashTableInit(HashTable* ht) { assert(ht); ht->_N = GetNextPrimeNum(0); ht->_tables = (HashNode**)malloc(sizeof(HashNode*)*ht->_N); ht->_size = 0; for (int i = 0; i < 53; i++) { ht->_tables[i] = NULL; } return; }0而是将每个位置变成NULL。
int HashTableInsert(HashTable* ht, KeyType key, ValueType value) { assert(ht); HashNode *cur = NULL; HashNode *next = NULL; int Index = 0; Index = HashFunc(key, ht->_N); cur = ht->_tables[Index]; if (cur == NULL) { ht->_tables[Index] = BuyHashNode(key, value); return 1; } else { while (cur) { if (cur->_key == key) { return 0; } cur = cur->_next; } next = ht->_tables[Index]->_next; ht->_tables[Index] = BuyHashNode(key, value); ht->_tables[Index]->_next = next; } ht->_size++; return 1; }
HashNode* HashTableFind(HashTable* ht, KeyType key) { assert(ht); int Index = HashFunc( key, ht->_N); HashNode *cur = ht->_tables[Index]; while (cur) { if (cur->_key == key) return cur; cur = cur->_next; } return NULL; }int HashTableRemove(HashTable* ht, KeyType key) { assert(ht); int Index = HashFunc(key, ht->_N); HashNode *cur = NULL; HashNode *prev = NULL; cur = ht->_tables[Index]; while (cur) { if (cur->_key == key) { if (prev == NULL)//第一个位置 { ht->_tables[Index] = cur->_next; } else//不是第一个 { prev->_next = cur->_next; } free(cur); ht->_size--; return 0; } prev = cur; cur = cur->_next; } return -1; }size_t GetNextPrimeNum(size_t cur) { int i = 0; static const unsigned long _PrimeList[28] = { 53ul, 97ul, 193ul, 389ul, 769ul, 1543ul, 3079ul, 6151ul, 12289ul, 24593ul, 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, 1610612741ul, 3221225473ul, 4294967291ul }; for (i = 0; i < 28; i++) { if (_PrimeList[i]>cur) return _PrimeList[i]; } }1不能被任何一个数整除,又因为我们的映射方式就是采用了余数法,所以这里素数的话就能在一定程度上缓解哈希冲突。
int HashTableRemove(HashTable* ht, KeyType key) { assert(ht); int Index = HashFunc(key, ht->_N); HashNode *cur = NULL; HashNode *prev = NULL; cur = ht->_tables[Index]; while (cur) { if (cur->_key == key) { if (prev == NULL)//第一个位置 { ht->_tables[Index] = cur->_next; } else//不是第一个 { prev->_next = cur->_next; } free(cur); ht->_size--; return 0; } prev = cur; cur = cur->_next; } return -1; }void HashTableDestory(HashTable* ht) { int i = 0; HashNode *cur = NULL; HashNode *next = NULL; for (; i < ht->_N; i++) { cur = ht->_tables[i]; while (cur) { next = cur->_next; free(cur); cur = next; } } free(ht->_tables); ht->_N = 0; ht->_size = 0; } HashTable *Check(HashTable* ht) { if (ht->_N*0.7 < ht->_size) { HashTable NewHt; HashTableInit(&NewHt); HashNode *cur = NULL; int i = 0; for (; i < ht->_N; i++) { cur = ht->_tables[i]; while (cur) { HashTableInsert(&NewHt, cur->_key, cur->_value); } } HashTableDestory(ht); return &NewHt; } else { return NULL; } }1,给她分配好了空间,然后插入到了第一个指针数组中,当扩容的时候就可以直接把这里链表直接连接过去,但是可以直接将数组下边的一串直接对应到新的数组对应的位置吗?不行,为什么因为你扩充数组的时候,每个数据要对应的位置也发生了变化所以你需要读取数据后算出他对应的新位置,然后直接将这个结构体摘下来放到新的指针数组里边不需要再给他们重新开辟空间了,这是一个方便的相对办法。这里我没有写出来。
O(1),但是这是一个十分理想的情况才能达到的状态。哈希开放定址法的时候我们会有负载因子,一般是0.7也就是说,当你的元素占了数组总元素百分之七十的时候,就需要进行扩充你的数组长度,但是这里可以适当的扩大你的负载因子可以扩充到1。
文章来源: 哈希拉链法(哈希桶)