java中的数据结构——哈希表

哈希表

哈希法是一个用于唯一标识对象并将每个对象存储在一些预先计算的唯一索引(键)中的过程,因此, 对象以键值对的形式存储,键值对的集合称为字典,可以使用键搜索每个对象。哈希法有很多不同的数 据结构,但最常用的是哈希表。 哈希表通常使用数组实现,它可以提供快速的查找和插入操作,哈希表不仅速度快(比树快),编程实 现也相对容易。
缺点:基于数组,数组创建后难以扩展,某些哈希表被基本填满时,性能下降的非常严重,所以必须要 清楚表中要存储多少数据,而且,也没有一种简便的方法可以以任何一种顺序遍历表中数据项。 如果不需要有序遍历数据,并且可以提前预测数据量的大小,那么哈希表在速度和易用性方面都很好。

散列数据结构的性能取决于以下三个因素。哈希函数,哈希表的大小,碰撞处理方法。
如何把关键字转换成数组下标? 在哈希表中,这个转换通过哈希函数来完成,对于特定的关键字,并不需要哈希函数,关键字的值可以 直接用于数组下标(关键字作为索引)。使用基于数组的数据库,会使得存储数据速度快且非常简单。
若关键字不能恰好用于数组下标时,如何使用哈希函数进行转换? 字典 在一些计算机语言的编译器中,通常用哈希表保留符号表(记录遍历和函数名及内存中的地址)。
效率: 不论哈希表中有多少数据,插入和删除只需要接近常量的时间,即O(1)的时间级,实际上,这只需要几 条机器指令。
扩展数组: 当哈希表变得太满时,就需要扩展数组。

在java中,数组有固定的大小,而且不能扩展,编程时只能另 外创建一个新的更大的数组,然后把旧数组的所有内容插入到新的数组中。哈希函数根据数组大小计算 给定数据项的位置,所以这些数据项不能在放到新数组中和老数组相同的位置上。因此,不能简单的从 一个数组向另一个数组拷贝数据,需要按顺序遍历老数组,用insert方法向新数组中插入每个数据项, 这就是重新哈希化,这是一个耗时的过程,但是如果数组一定要进行扩展,那么就必须进行这个过程。 扩展后的数组容量通常是原来的两倍。

哈希函数: 好的哈希函数很简单,所以它能快速计算。哈希表的主要优点是它的速度,如果哈希函数运行缓慢,速 度就会降低,哈希函数中有很多乘法和除法是不可取的。哈希函数的目的是得到关键字值的范围,把它 用一种方式转化成数组的下标值,这种方法应该使关键字值随机的分布在整个哈希表中。关键字可能随 机,也可能不随机。
哈希化和外部存储 磁盘由许多包含文件的块组成,存取一个块的时间比任何在内存中存取数据的时间都要长的多,因此, 在设计外部存储策略时,不考虑最小化存取块的数量。而且,外部存储器单位容量很便宜,所以,可以 使用更大数量的存储器,超过要存取的项数,如果这样,会加快存取时间,这就有可能使用哈希表。 文件指针表 外部哈希化的关键部分是一个哈希表,它包含块成员,指向外部存储器中的块。哈希表有时叫做索引, 它可以存储在内存中,如果太大,也可以存储在磁盘上,而把它的一部分放在内存中,即使把哈希表都放在内存中,也要在磁盘保存一个备份,文件打开时,把它存入内存。 未填满块 在外部哈希化中,重要的是块不要填满。所有关键字映射为同一个值的记录都定位到相同块。为找到特 定关键字的一个记录,搜索算法哈希化关键字,用哈希值作为哈希表的下标,得到某个下标中的块号, 然后读取这个块。定位一个特定的数据项,只需要访问一次块。缺点是很多的磁盘空间被浪费了,因为 设计时规定,块是不允许填满的。所以必须仔细选择哈希函数和哈希表的大小,为的是限制映射到相同 的值关键字的数量。 填满的块 即使用一个好的哈希函数,块偶尔也会填满。这时,可以使用在内部哈希表中处理冲突的不同方法:开 放地址法和链地址法。
开放地址法:插入时,如果发现一个块是满的,算法在相邻的块插入新记录,在线性探测中,这是下一 个块,但也可以用二次探测或再哈希法选择。 在链地址法中,有一个溢出块,当发现块已满时,新记录插在溢出块中。 填满的块是不合乎需要的,因为有了它就需要额外的磁盘访问,这就需要两倍的访问时间,如果这种情 况不经常发生也可以忽略。

上一篇:java中的数据结构——队列
下一篇:java中的数据结构——链表

猜你喜欢

转载自blog.csdn.net/lx_Frolf/article/details/83277161
今日推荐