哈希——拉链法
2018-03-01 15:25
357 查看
首先写哈希——拉链法要知道哈希冲突。
哈希冲突: 对于两个数据元素的关键字 Ki 和 Kj (i != j),有 Ki != J ,但有: HashFun(Ki) == HashFun(Kj) 即不同关键字通过相同哈希哈数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞。把具有不同关键码而具有相同哈希地 址的数据元素称为“同义词”所以解决哈希冲突两种常见的方法是:闭散列和开散列
本文主要介绍开散列——拉链法:
开散列法:首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每一个子集合称为一个桶,各个 桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中。
首先定义结构体:
typedef int Keytype; typedef int Valtype; typedef struct HashNode { HashNode *_next; Keytype _key; Valtype _val; }HashNode; typedef struct HashTable { HashNode **_table; size_t _N; size_t _size; }HashTable;
函数定义:
HashNode *HashBuyNode(Keytype key,Valtype val)//创建节点 { HashNode *node=(HashNode*)malloc(sizeof(HashNode)); node->_key=key; node->_val=val; node->_next=NULL; assert(node); return node; } size_t HashFunc(Keytype key,size_t n)//这个函数主要作用就是判断要查找的数在哪个哈希桶里 { return key%n; } size_t GetNextPrime(size_t cur)//获取素数N,进行扩容时用到的 { const int _PrimeSize = 28; static const unsigned long _PrimeList[_PrimeSize] = {//素数表 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 (size_t i = 0; i < _PrimeSize; ++i) { if (_PrimeList[i] > cur) { return _PrimeList[i]; } } return _PrimeList[_PrimeSize - 1]; } void HashTableInit(HashTable *ht)//初始化 { assert(ht); ht->_size=0; ht->_N=53; ht->_table=(HashNode**)malloc(sizeof(HashNode*)*ht->_N); memset(ht->_table,NULL,sizeof(HashNode*)*ht->_N);//都置为空 }
哈希——拉链法插入:(扩容是重点部分,每次扩容后插入的数的坐标需重新计算)
int HashTableInsert(HashTable *ht,Keytype key,Valtype val)//拉链法的插入 { //扩容需要重新开辟空间 if (ht->_size==ht->_N)//扩容 { size_t newN=GetNextPrime(ht->_N); HashNode **newTable=(HashNode**)malloc(sizeof(HashNode*)*newN); memset(newTable,NULL,sizeof(HashNode*)*newN); for (size_t i=0;i< ht->_N ;i++) { HashNode *cur=ht->_table[i]; while (cur) { //HashNode *next=cur->_next; size_t Newindex=HashFunc(cur->_key,newN); //头插 cur->_next=newTable[Newindex]; newTable[Newindex]=cur; cur=cur->_next; } } free(ht->_table);//释放原哈希表 ht->_table=newTable; ht->_N=newN; } size_t index=HashFunc(key,ht->_N);//找出该数在哪个哈希表里 HashNode *cur=ht->_table[index];//判断是否包含 while (cur) { if (cur->_key==key) { return -1; } cur=cur->_next; } //进行插入 应用头插法 HashNode *node=HashBuyNode(key,val); node->_next= ht->_table[index]; ht->_table[index]=node; ++ht->_size; return 0; }
哈希——拉链法的寻找与删除:
HashNode *HashTableFind(HashTable *ht,Keytype key) { size_t index=HashFunc(key,ht->_N); HashNode*cur=ht->_table[index]; while(cur) { if (cur->_key==key) { return cur; } cur=cur->_next; } return NULL; } int HashTableRemove(HashTable *ht,Keytype key)//移除 { size_t index=HashFunc(key,ht->_N); HashNode *cur=ht->_table[index]; HashNode *prev=NULL; while (cur) { if (cur->_key==key) { if (prev==NULL) { ht->_table[index]=cur->_next; } else { prev->_next=cur->_next; } free(cur); cur=NULL; --ht->_size; return 0; } prev=cur; cur=cur->_next; } return -1; }
哈希——打印函数:
void HashPrint(HashTable *ht)//打印哈希表 { for (size_t i=0;i< ht->_N ;i++) { HashNode *cur=ht->_table[i]; printf("[%d]",i); while(cur) { printf("%d->",cur->_key); cur=cur->_next; } if (cur==NULL) { printf("NULL\n"); } } }
测试用例:
int main() { HashTable ht; HashTableInit(&ht); HashTableInsert(&ht,1,2); HashTableInsert(&ht,1,2); HashTableInsert(&ht,2,2); HashTableInsert(&ht,3,2); HashTableInsert(&ht,54,2); HashTableRemove(&ht,3); HashPrint(&ht); system("pause"); }
相关文章推荐
- 哈希桶的实现(拉链法)
- 哈希表的实现(闭散列法和拉链法)
- 哈希(不可逆)加密通用类库函数
- C#的哈希
- 数据结构——杂凑表(拉链法)
- 推荐一款哈希计算工具(可用于镜像文件校验)
- 算法 哈希(hash——map)
- 字典、哈希与Map(嵌套map非常管用)
- 哈希表的应用
- 嵌入式linux c 学习笔记9---哈希链表
- 哈希的原理和代价
- 哈希(Hash)与加密(Encrypt)的基本原理、区别及工程应用
- poj3274数组的哈希
- hashcode Java 理论与实践: 哈希
- 写了个散列算法... 用来获取字符串的哈希. 超高效.10亿以下几乎无碰撞.
- 基于哈希表构建高效 矩阵存储结构--矩阵的一种存储方法 哈希矩阵。
- 哈希查找和二分法
- 迭代哈希
- 哈希聚簇读取(Hash Cluster Access)[摘]
- 哈希查找的应用之打印c++源文件中关键字和函数名