哈希表和哈希函数介绍

   

哈希表   

       什么是哈希表(hash table)?给定表M,若存在函数h(key),使得对任意给定的关键字值key,代入函数后能得到包含该key的记录在表中的地址,则称表M为哈希表或者散列表。函数h(key)为哈希函数或者散列函数。哈希函数的好坏会直接影响哈希表的优劣。

      散列表是由哈希函数和数组共同构建的一种数据结构,元素由键和值组成。散列表中的一个位置称为槽位(slot)或者(bucket),用于保存键值对。由哈希函数映射的数组下标称为散列地址(桶号),决定了给定的键存于散列表的哪个桶中。如果不同的key映射到了相同的数组下标,则发生了哈希碰撞(hash collision)。数组中的元素可以是一个链表或者一棵红黑树等数据结构,链表或者红黑树用来解决哈希碰撞。散列表所拥有的桶数被称为散列表的容量(capacity)。 举个例子,我们要在哈希表中执行插入操作:

        图中,0-5标记部分即代表哈希表,如果不同的 key 映射到了同一数组下标,就将其放入对应数组下标的单链表中。例如,令关键字 key=kobe,则通过哈希函数f(key)得到其槽位为1,故把 kobe 放在数组下标为1的桶中。

        Java 的集合中给出了底层结构采用哈希表数据结构的实现类,按照时间顺序分别为第一代Hashtable、第二代 HashMap和第三代 ConcurrentHashMap。它们的相同点:底层结构都是哈希表,都是用来存储 key-value 映射,都实现了 Map 接口。

五种数据结构

       为了便于理解散列表,下面粗略地介绍下四类数据结构在新增,查找等基础操作中的执行性能。

       数组:存储区间连续,占用内存严重,寻址容易,插入删除困难;对于指定下标的查找,复杂度为O(1);对于给定值进行查找,需要遍历数组,复杂度为O(n),对于一般的插入删除操作,涉及到数组元素的移动,其平均复杂度也为O(n)。

       线性链表:存储区间散列,占用内存比较宽松,寻址困难,插入容易。对于链表的新增,删除等操作(在找到指定操作位置后),仅需处理结点间的引用即可,复杂度为O(1),而查找操作需要遍历链表逐一进行比对,复杂度为O(n)。

       哈希表(Hash table,也叫散列表):相比上述几种数据结构,在哈希表中进行添加,删除,查找等操作,性能十分之高,不考虑哈希冲突的情况下,仅需一次定位即可完成,复杂度为O(1)。 

       二叉树:对一棵相对平衡的有序二叉树,对其进行插入,查找,删除等操作,平均复杂度均为O(logn)。

       红黑树先来看下《算法导论》对R-B Tree的介绍:红黑树是一棵二叉搜索树,它在每个节点增加了一个存储位记录节点的颜色,可以是红色,也可以是黑色;通过任意一条从根到叶子节点的路径上颜色的约束,红黑树保证最长路径不超过最短路径的二倍,因而近似平衡。红黑树,作为一棵二叉查找树,满足二叉查找树的一般性质。具体性质如下:

 

1. 每个节点的颜色要么是黑色,要么是红色;
2. 根节点是黑色的;
3. 每个叶子节点(叶结点即指树尾端NIL指针或NULL结点)都是黑的。
4. 每个红色节点的两个子节点一定都是黑色。(没有连续的红节点);
5. 对于任意节点而言,其到叶子节点的每条路径都包含相同数目的黑色节点。 
 
      从性质5又可以推出:如果一个节点存在黑子节点,那么该节点肯定有两个子节点。 
 

 

 

      此图忽略了叶子节点和根部的父结点。其中Nil为叶子结点,并且它是黑色的。 

哈希表的优缺点

      哈希表的优点显而易见,能够在常数级的时间复杂度上进行查找,并且插入数据和删除数据比较容易。但是它也有缺点,例如不支持排序,一般比用线性表存储需要更多的空间,并且记录的关键字不允许重复。

  

posted @ 2020-03-29 19:26  楼兰胡杨  阅读(471)  评论(0编辑  收藏  举报