查找(3)--哈希表(散列查找)

来源:互联网 发布:win7网络图标无法打开 编辑:程序博客网 时间:2024/05/19 12:27

一.基本概念:

            1. 哈希查找(散列查找),与前面介绍的静态查找和动态查找方法完全不同,前面介绍的所有查找都是基于待查关键字与表中元素进行比较而实现的查找方法,而散列查找是通过构造哈希函数来得到待查关键字的地址,按理论分析真正不需要用到比较的一种查找方法。

            2.哈希表定义:根据设定的哈希函数 H(key) 和所选中的处理冲突的方法,将一组关键字映象到一个有限的、地址连续的地址集 (区间) 上,并以关键字在地址集中的“象”作                                        为相应记录在表中的存储位置,如此构造所得的查找表称之为“哈希表”

            3.举例来说明:

                            假设有一批关键字序列18,75,60,43,54,90,46,给定哈希函数H(k)=k%13,存贮区的内存地址从0到15,则可以得到每个关键字的散列地址为:

                    H(18)=18%13=5,H(75)=75%13=10,H(60)=60%13=8,H(43)=43%13=4,H(54)=54%13=2,H(90)=90%13=12, H(46)=46%13=7,

                    于是,根据散列地址,可以将左边7个关键字序列存贮到一个一维数组HT(哈希表或散列表)中,具体表示为:

                                           例如查找元素:查找75,只需计算出H(75)=75%13=10,则可以在HT[10]中找到75。


                            上面讨论的哈希表是一种理想的情形,即每一个关键字对应一个唯一的地址。但是有可能出现这样的情形,两个不同的关键字有可能对应同一个内存地址,即两                 个记录的关键值不等,但它们的哈希函数的值相同,这样,将导致后放的关键字无法存贮,我们把这种现象叫做冲突  

                使用哈希方法,首先要选择一个好的哈希函数,使一组关键值所得到的哈希地址能均匀分布在整个地址空间中,并且冲突次数尽可能地少。

            4.发生冲突的可能性却与三个方面因素有关

                        第一:是与装填因子α有关,所谓装填因子是指哈希表中己存入的元素个数n与哈希表的大小m的比值,即α=n/m。当α越小时,发生冲突的可能性越小,α越 (最                                       大为1)时,发生冲突的可能性就越大。但是,为了减少冲突的发生,不能将α变得太小,这样将会造成大量存贮空间的浪费,因此必须兼顾存储空间和                                        冲突两个方面。
                        第二:是与所构造的哈希函数有关(前面己介绍)。
                        第三:是与解决冲突的方法有关。


二.哈希函数的构造

             1.直接定址法 
                           可表示为H(k)=a.k+b,其中a、b均为常数。
                           这种方法计算特别简单,并且不会发生冲突,但当关键字分布不连续时,会出现很多空闲单元,将造成大量存贮单元的浪费

             2.数字分析法
                           对关键字序列进行分析,取那些位上数字变化多的、频率大的作为哈希函数地址。

                            例如: 有如下的关键字序列     9 9 3 4 6 5 3 2
                                                                                  9 9 3 7 2 2 4 2

                                                                                  9 9 3 8 7 4 3 2.......通过对上述关键字序列分析,发现前3位相同,第8位只取2,因此,这四位不可取。中间的四位的数字变化多                                                                                                                       些,可看成是随机的,若规定地址取3位,则哈希函数可取它的第4、5、6位。于是有:
                                                                                                                    H(99346532)=465 ,H(99372242)=722,H(99387433)=874

             3.平方取中法
                               取关键字平方后的中间几位为哈希函数地址。这是一种比较常用的哈希函数构造方法,但在选定哈希函数时不一定知道关键字的全部信息,取其中哪几位也不                               一定合适,而一个数平方后的中间几位数和数的每一位都相关,因此,可以使用随机分布的关键字得到哈希函数地址。

            4.折叠法
                             将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位)作为哈希函数地址,称为折叠法

                             例如,假设关键字为某人身份证号码430104681015355,则可以用4位为一组进行叠加,即有5355+8101+1046+430=14932,舍去高位,则有     

                                        H(430104681015355)=4932为该身份证关键字的哈希函数地址。

            5.除留余数法
                          该方法是用关键字序列中的关键字k除以一个整数p所得余数作为哈希函数的地址,即
                           H(k)=k%p 。   P<=m   m为哈希表长度

                            除留余数法计算简单,适用范围广,是一种最常使用的方法。这种方法的关键是选取较理想的p值,使得每一个关键字通过该函数转换后映射到散列空间上任一                    地址的概率都相等,从而尽可能减少发生冲突的可能性。一般情形下,p 取为一个素数较理想,并且要求装填因子α最好是在0.6∽0.9之间,所以p 最好取1.1n∽1.7n                    之间的一个素数较好,其中n为哈希表中待装元素个数。

            6.  随机法
                        选择一个随机函数,取关键值的随机函数值为它的哈希地址,即 H(key)=random(key)
                          random()不能是一般的随机函数,固定的参数必须返回确定的值。


三. 解决冲突的方法

             1.开放定址法
                           开放定址法就是从发生冲突的那个单元开始,按照一定的次序,从哈希表中找出一个空闲的存储单元,把发生冲突的待插入关键字存储到该单元中,从而解决冲                              突的发生。在哈希表未满时,处理冲突需要的“下一个”空地址在哈希表中解决。
                           开放定址法利用下列公式求“下一个”空地址
                                   Hi=(H(key)+di) MOD m     i=1,2,…K(K<=m-1)    其中H(key)为哈希函数,m为哈希表长度,di为增量序列。

              根据di的取法,解决冲突时具体使用下面一些方法。

                            (1)线性探测法:

                                      假设哈希表的地址为0∽m-1,则哈希表的长度为m。若一个关键字在地址d处发生冲突,则依次探查d+1,d+2,…,m-1(当达到表尾m-1时,又从0,1,                                       2,….开始探查)等地址,直到找到一个空闲位置来装冲突处的关键字,将这一种方法称为线性探查法。假设发生冲突时的地址为d0=H(k),则探查下一位                                         置的公式为di=(di-1+1)%m (1≤i≤m-1),最后将冲突位置的关键字存入di地址中。

                                       例:  给定关键字序列为19,14,23,1,68,20,84,27,55,11,10,79,哈希函数H(k)=k%13 ,哈希表空间地址为0∽12,试用线性探查法建                                                    立哈希存贮(哈希表)结构。
                                                   得到的哈希表如下图所示:

                                                             

                            (2) 二次方探查法
                                         该方法规定,若在d地址发生冲突,下一次探查位置为d+12,d-12,d+22,d- 22, …,直到找到一个空闲位置为止。
                                         开放地址法充分利用了哈希表的空间,但在解决一个冲突时,可能造成下一个冲突。另外,用开放地址法解决冲突不能随便对结点进行删除。

                2. 链地址法
                           链地址法也称拉链法,是把相互发生冲突的同义词用一个单链表链接起来,若干组同义词可以组成若干个单链表 

                           例:对给定的关键字序列19,14,23,1,68,20,84,27,55,11,10,79,给定哈希函数为H(k)=k%13,试用拉链法解决冲突建立哈希表。

                            


四.哈希查找的性能分析:

                    哈希查找按理论分析,它的时间复杂度应为O(1),它的平均查找长度应为ASL=1,但实际上由于冲突的存在,它的平均查找长度将会比1大。下面将分析几种方法的                     平均查找长度。

     1.线性探查法的性能分析
                由于线性探查法解决冲突是线性地查找空闲位置的,平均查找长度与表的大小m无关,只与所选取的哈希函数H及装填因子α的值和该处理方法有关,这时的成功的平 均 查找长度为ASL=1/2 (1+1/(1- α)) 。

2.拉链法查找的性能分析
由于拉链法查找就是在单链表上查找,查找单链表中第一个结点的次数为1,第二个结点次数为2,其余依次类推。它的平均查找长度ASL=1+α/2。 


查找综合练习题:

             例:给定关键字序列11,78,10,1,3,2,4,21,试分别用顺序查找、二分查找、二叉排序树查找、哈希查找(用线性探查法和拉链法)来实现查找,试画出它们的对应存储形式(顺序查找的顺序表,二分查找的判定树,二叉排序树查找的二叉排序树,哈希查找的哈希表),并求出每一种查找的成功平均查找长度。哈希函数H(k)=k%11。

             (1)顺序查找:

                        顺序查找的顺序表(一维数组)如下所示,

                          

                         从上图可以得到顺序查找的成功平均查找长度为:
                                              ASL=(1+2+3+4+5+6+7+8)/8=4.5;

              (2)二分查找:

                           二分查找的判定树(中序序列为从小到大排列的有序序列)如下图所示, 

                           

                           从上图可以得到二分查找的成功平均查找长度为:
                           ASL=(1+2*2+3*4+4)/8=2.625;

             (3).二叉排序树(关键字顺序已确定,该二叉排序树应唯一)如下图所示, 

                                  

                              从上图可以得到二叉排序树查找的成功平均查找长度为:
                              ASL=(1+2*2+3*2+4+5*2)=3.125;

               (4)线性探查法解决冲突的哈希表如下图所示, 

                                    

                         从上图可以得到线性探查法的成功平均查找长度为:
                           ASL=(1+1+2+1+3+2+1+8)/8=2.375;

              (5)拉链法解决冲突的哈希表如下图所示。

                            

              从上图可以得到拉链法的成功平均查找长度为:
             ASL=(1*6+2*2)/8=1.25。

0 0