分离链接法

解决冲突的第一种方法通常叫作分离链接法(separate chaining),其做法是将散列到同一个值的所有元素保留在一个表中。为方便起见这些表都有表头。如果空间很紧,则更可取的方法是避免使用这些表头。

为执行Find,我们使用散列函数来确定究竟考察哪个表。此时我们以通常的方式遍历该表并返回所找到的被查找项所在位置。为执行Insert,我们遍历一个相应的表以检查该元素是否已经处在适当的位置(如果要插入重复元,那么通常要留出一个额外的域,这个域当重复元出现时增1)。如果这个元素是新的元素,那么插入到表的前端,或者插入到表的末尾,哪个容易就执行哪个。有时将新元素插入到表的前端不仅因为方便,而且还因为新近插入的元素最有可能最先被访问。

类型声明:

#define MinSize (10)
typedef unsigned int Index;
typedef struct HashTbl* HashTable;
typedef struct ListNode* PtrToNode;
typedef PtrToNode List;
typedef PtrToNode Position;
typedef int ElementType;
struct HashTbl
{int tableSize;List* theLists;
};struct ListNode
{ElementType element;Position next;
};

初始化:

第8行可以改进,自定义一个函数NextPrime,用于找到并返回Size的下一个素数。然后我们把这个素数用作实际表大小赋值给h->tableSize。

HashTable InitializeTable(int tableSize)
{int i;//Allocate tableHashTable h = (HashTable)malloc(sizeof(struct HashTbl));if (h == NULL)return NULL;h->tableSize = tableSize > MinSize ? tableSize : MinSize;//Allocate array of listsh->theLists = (List*)malloc(h->tableSize * sizeof(List));if (h->theLists == NULL)FatalError("out of space");//Allocate list headersfor (i = 0; i < h->tableSize; i++){h->theLists[i] = (PtrToNode)malloc(sizeof(struct ListNode));if (h->theLists[i] == NULL){FatalError("out of space!");}elseh->theLists[i]->next = NULL;}return h;
}

散列函数、查找与检索:

这里直接用的简单的散列函数,查找例程中的第十行有必要说明一下,它的循环是找到表的末尾即NULL处停止,或者找到不为NULL,且节点的元素值与关键字值相等时停止。所以没找到key时,tmpNode会返回NULL,找到了返回元素值与key相等的节点的地址。(为简单起见我们这里的元素值和关键字都为int,一般来说还可能为字符串,字符串的比较就需要用到strcmp)

检索例程中检索错误我是用返回 INT_MAX表示,但是实际上应该写成报错。

Index Hash(HashTable h, ElementType key)
{return key % h->tableSize;
}
Position Find(HashTable h, ElementType key)
{if (h == NULL)return NULL;unsigned int index = Hash(h, key);Position tmpNode = h->theLists[index]->next;while (tmpNode != NULL && tmpNode->element != key)tmpNode = tmpNode->next;return tmpNode;
}
ElementType Retrieve(Position p)
{if (p != NULL)return p->element;elsereturn INT_MAX;
}

插入:

如果要插入的项已经存在,那么我们就什么也不做,否则我们把它放到表的前端。tmpNode的值可以通过直接调用Find函数得到,但是这样的话就会多一次散列函数的运算,如果散列函数构成了程序运行时间的重要部分,就应该避免多次计算。

void Insert(HashTable h, ElementType key)
{if (h == NULL)return;unsigned int index = Hash(h, key);List L = h->theLists[index];Position tmpNode = L->next;while (tmpNode != NULL & tmpNode->element != key)tmpNode = tmpNode->next;if (tmpNode == NULL){tmpNode = (PtrToNode)malloc(sizeof(struct ListNode));if (tmpNode == NULL){printf("out of space");return;}else{tmpNode->element = key;tmpNode->next = L->next;L->next = tmpNode;}}
}

删除:

void Delete(HashTable h, ElementType key)
{if (h == NULL)return;unsigned int index = Hash(h, key);Position prevNode = h->theLists[index];Position tmpNode = prevNode->next;while (tmpNode != NULL && tmpNode->element != key){prevNode = tmpNode;tmpNode = tmpNode->next;}//Key was foundif (tmpNode != NULL){prevNode->next = tmpNode->next;free(tmpNode);}
}

销毁表:

此例程编写需要格外仔细,稍不注意就可能释放不完全而导致内存泄漏。

void DestroyTable(HashTable h)
{if (h == NULL)return;int i;Position tmpNode, nextNode;for (i = 0; i < h->tableSize; i++){tmpNode = h->theLists[i];while (tmpNode != NULL){nextNode = tmpNode->next;free(tmpNode);tmpNode = nextNode;}}free(h->theLists);free(h);
}

我们定义散列表的装填因子(load factor)为散列表中的元素个数与散列表大小的比值。表的平均长度为。执行一次查找所需要的工作是计算散列函数值所需要的常数时间加上遍历表所用的时间。在一次不超过的查找中,遍历的链接数平均为(不包含最后的NULL链接)。成功的查找则需要遍历大约;它保证必然会遍历一个链接(因为查找是成功的),而我们也期望沿着一个表中途就能找到匹配的元素。这就指出,表的大小实际上并不重要,而装填因子才是重要的。分离链接散列的一般法则是使得表的大小尽量与预料的元素个数差不多(换句话说,让≈1)。正如前面提到的,使表的大小是素数以保证一个好的分布,这也是一个好的想法

散列表ADT--分离链接法相关推荐

  1. Python与数据结构[4] - 散列表[1] - 分离链接法的 Python 实现

    分离链接法 / Separate Chain Hashing 前面完成了一个基本散列表的实现,但是还存在一个问题,当散列表插入元素冲突时,散列表将返回异常,这一问题的解决方式之一为使用链表进行元素的存 ...

  2. 【数据结构笔记40】哈希表冲突处理方法:开放地址法(线性探测、平方探测、双散列、再散列),分离链接法

    本次笔记内容: 11.3.1 开放定址法 11.3.2 线性探测 11.3.3 线性探测-字符串的例子 11.3.4 平方探测法 11.3.5 平方探测的实现 11.3.6 分离链接法 文章目录 冲突 ...

  3. 6-23 分离链接法的删除操作函数 (20 分)

    试实现分离链接法的删除操作函数. 函数接口定义: bool Delete( HashTable H, ElementType Key ); 其中HashTable是分离链接散列表,定义如下: type ...

  4. 分离链接法的删除操作函数

    习题5.11 分离链接法的删除操作函数 (20 分) 试实现分离链接法的删除操作函数. 函数接口定义: bool Delete( HashTable H, ElementType Key ); 其中H ...

  5. 冲突处理方法----分离链接法

    1 前言 常用处理冲突的思路: 换个位置: 开放地址法 同一位置的冲突对象组织在一起:链地址法 2 分离链接法 分离链接法:将相应位置上冲突的所有关键词存储在同一个单链表中 举例说明最直接:设关键字序 ...

  6. 数据结构之哈希表的分离链接法java实现

    哈希表的分离链接法 原理 Hash Table可以看作是一种特殊的数组.他的原理基本上跟数组相同,给他一个数据,经过自己设置的哈希函数变换得到一个位置,并在这个位置当中放置该数据.哦对了,他还有个名字 ...

  7. 散列表(开放定址法)

    散列表(开放定址法) 1.线性探测法 将具体的值输入到哈希函数中,映射出的具体的哈希表中的下标索引.当下标索引冲突时. 离散链表法:将重复了的值用链表的方式挂在对应索引的链表下. 线性探测法:一个位置 ...

  8. 散列表(离散链表法)

    散列表(离散链表法) 1.相关介绍 散列表也叫哈希表,英文名字Hash Table,有具体的哈希函数,将值映射到具体的表下标中.这样查找起来就十分方便. 散列表的注意点: (1)散列函数要具有一致性, ...

  9. 散列表,(拉链法,平方探测法,线性探测法)

    840. 模拟散列表 题目 提交记录 讨论 题解 视频讲解 维护一个集合,支持如下几种操作: I x,插入一个数 x : Q x,询问数 x 是否在集合中出现过: 现在要进行 N 次操作,对于每个询问 ...

最新文章

  1. 让wordpress首页不显示指定分类文章
  2. 皮一皮:智商捉急...
  3. [数据分析][评价方法]打分式评价-信息熵理论与熵权法
  4. 无线网络连接无法停用
  5. python中的os操作文件,文件路径
  6. React Native使用指南-原生UI组件
  7. Together(AtCoder-3524)
  8. 阿里云面向制造业推出防疫复工数字化方案 复工效率提升50%以上
  9. c向python注册函数_python如何调用C, 如何注册成C的回调函数(python后台程序常用方法)...
  10. php中array_merge函数
  11. 利用清华镜像、阿里云镜像与豆瓣镜像pip资源
  12. 了解Android布局,了解Android对话框布局
  13. linux防火墙查看状态firewall、iptable
  14. 扫码枪 android EditText
  15. STM32学习心得三十三:FLASH闪存编程原理与实验
  16. 促使网站快速收录的一些方法,超详细
  17. Solver Prototxt - 参数说明
  18. 使用 Learner Lab - 学生
  19. 安卓中的布局优化之clude、merge、ViewStub
  20. Xshell的Sessions存放目录

热门文章

  1. 卸载 npm 软件包
  2. php开发telegram机器人接收机器人收到的消息
  3. Unity3d优化总结2
  4. Eclipse创建java web工程
  5. 【超简易】网站ioc图标添加【超详细】
  6. (称重问题)假设你有8个球,其中一个略微重一些,但是找出这个球的惟一方法是将两个球放在天平上对比
  7. 几款好用播放器ijkplayer、vlc、SmartPlayer、ExoPlayer
  8. Android Studio生成二维码
  9. 揪出占用电脑C盘的元凶“微信”,立马清爽了
  10. 問題の解決策 [USACO18JAN]Lifeguards P(题解)