【算法视频】:哈希查找--线性探测法

1.3.1、哈希查找-线性探测法


资讯网址:www.qghkt.com

腾讯课堂:https://qghkt.ke.qq.com/20个常用算法


根据设定的哈希函数Hash(key)和处理冲突的方法,将一组关键码映射到一个有限的连续的地址集(区间)上,并以关键码在地址集中的“像”作为记录在表中的存储位置,这种表称为哈希表,这一映射过程称为哈希造表或散列,所得的存储位置称为哈希地址或散列地址。

       对于某个哈希函数Hash和两个关键码K1和K2,如果K1≠K2而Hash(K1)=Hash(K2),则称为出现了冲突,对该哈希函数来说,K1和K2称为同义词。

       一般情况下,冲突不能完全避免,只能尽可能地去减少冲突,因此在建造哈希表时不仅要设定一个“好”的哈希函数,而且要设定处理冲突的方法。

其中,Hash(key)为哈希函数;m为哈希表的表长;为增量序列。

常见的增量序列有如下3种:

①  =1,2,3,…,m-1,称为线性探测再散列

②  =,,,…,(k),称为二次探测再散列

③  =伪随机序列,称为随机探测再散列。

1)线性探测法

【基本思路】

1.1造哈希表

某记录的关键码为key,哈希函数值H(key)=j。若在哈希地址j发生了冲突(即此位置已存放了其他元素),则对哈希地址j+1进行探测,若仍然有冲突,再对地址j+2进行探测,依此类推,直到找到哈希表中的一个空单元并将元素存入表中为止。

1.2查找

a)       先根据哈希函数计算出元素的哈希地址

b)       若是空单元,说明查找不成功,可结束查找;若不是空单元,则与该单元中的元素进行比较。

c)       若相等,则查找成功并结束查找,否则,计算出下一个哈希地址,转b)。

【图解过程】

设关键码序列为47,34,19,12,52,38,33,57,63,21,哈希表表长为13,哈希函数为Hash(key) = key mod 11。

各关键码的哈希地址:

Hash(47) = 47 mod11 = 3,                    Hash(34) = 34mod 11 = 1,

Hash(19) = 19 mod11 = 8,                    Hash(12) = 12mod 11 = 1,

Hash(52) = 52 mod11 = 8,                    Hash(38) = 38mod 11 = 5,

Hash(33) = 33 mod11 = 0,                    Hash(57) = 57mod 11 = 2,

Hash(63) = 63 mod11 = 8,                    Hash(21) = 21mod 11 = 10,

(a)造哈希表,开始时为空表

哈希地址

0

1

2

3

4

5

6

7

8

9

10

11

12

关键码

 

 

 

 

 

 

 

 

 

 

 

 

 

(b)存关键码47,哈希地址为3,在该单元处无冲突,直接插入;然后依次将关键码34和19插入。

哈希地址

0

1

2

3

4

5

6

7

8

9

10

11

12

关键码

 

34

 

47

 

 

 

 

19

 

 

 

 

(c)存关键码12,哈希地址为1,此时有冲突,探测下一个单元(即哈希地址为2的单元)。

哈希地址

0

1

2

3

4

5

6

7

8

9

10

11

12

关键码

 

34

12

47

 

 

 

 

19

 

 

 

 

(d)存关键码52,哈希地址为8,也有冲突,探测下一个单元(即哈希地址为9的单元)。

哈希地址

0

1

2

3

4

5

6

7

8

9

10

11

12

关键码

 

34

12

47

 

 

 

 

19

52

 

 

 

(e)存关键码38,哈希地址为5,没有冲突;存关键码33,哈希地址为0,直接插入。

哈希地址

0

1

2

3

4

5

6

7

8

9

10

11

12

关键码

33

34

12

47

 

38

 

 

19

52

 

 

 

(f)存关键码57,哈希地址为2,有冲突,探测下一个单元(即哈希地址为3的单元,仍然有冲突,再探测下一个单元,即哈希地址为4的单元)。

哈希地址

0

1

2

3

4

5

6

7

8

9

10

11

12

关键码

33

34

12

47

57

38

 

 

19

52

 

 

 

(g)存关键码63,哈希地址为8,有冲突,探测下一个单元,仍有冲突,再探测下一个单元(即哈希地址为10的单元)。

哈希地址

0

1

2

3

4

5

6

7

8

9

10

11

12

关键码

33

34

12

47

57

38

 

 

19

52

63

 

 

(h)存关键码21,哈希地址为10,有冲突,探测下一个单元(哈希地址为11的单元)。

哈希地址

0

1

2

3

4

5

6

7

8

9

10

11

12

关键码

33

34

12

47

57

38

y

Z

19

52

63

21

X

线性探测法可能使第i个哈希地址的同义词存入第i+1个哈希地址,这样本应存入第i+1个哈希地址的元素变成了第i+2个哈希地址的同义词,……,因此,可能出现很多元素在相邻的哈希地址上“聚集”起来的现象,大大降低了查找效率。为此,可采用二次探测法或随机探测再散列法,以降低“聚集”现象。

【适用场景】

       依据记录的关键码直接得到其对应的存储位置,即要求记录的关键码与其存储位置之间存在一一对应关系,从而快速地找到记录。

【算法代码】

/****************************************************************

 * 函数名称:createHashTable

 * 功能描述:造线性探测法的哈希表

 * 参数说明:hashArr, 为造好的哈希表

 *                 hashLen,哈希表的表长

 *                 keyArr,原关键码的序列

 *                 keyLen,原关键码的序列的长度

 *                 modV,哈希函数的

 * 返回 值:void

 * 作    者:www.qghkt.com

 * 创建时间:

*****************************************************************

 * Copyright @ 清哥好课堂  All rightsreserved

*****************************************************************/

void createHashTable(inthashArr[], int hashLen, int keyArr[], int keyLen, int modV)

{

       //初始化  -1表示当前位置为空

       int i;

       for ( i = 0; i < hashLen; i++)

       {

              hashArr[i] = -1;

       }

       //造哈希表

       for ( i = 0; i < keyLen; i++)

       {

              int m = keyArr[i];

              int hashAdd = m % modV;

              while(hashAdd < hashLen)

              {

                     if (hashArr[hashAdd] ==-1)//是否为空

                     {

                            hashArr[hashAdd] =m;

                            break;

                     }

                     ++hashAdd;

                     //有可能要造循环的哈希表,即最后的位置被占用,从0位置开始重新探测

                     if (hashAdd == hashLen)

                     {//一定时哈希表的表长,大于等于keyArr的长度

                            hashAdd = 0;

                     }

              }

       }

}

/****************************************************************

 * 函数名称:hashSearch

 * 功能描述:线性探测法的哈希查找

 * 参数说明:hashArr, 哈希表

 *                 hashLen,哈希表的表长

 *                 value,所要查找的值

 *                 modV,哈希函数

 * 返回 值:如果不存在,返回-1,如果存在,则返回所在哈希表中的位置

 * 作    者:www.qghkt.com

 * 创建时间:

*****************************************************************

 * Copyright @ 清哥好课堂  All rightsreserved

*****************************************************************/

int hashSearch(inthashArr[], int hashLen, int value, int modV)

{

       int hashAdd = value % modV;

       int bj = hashAdd;  //是用来控制只找一圈

       //说明:原本的关键序列的长度和哈希表的长度是相等,即哈希表是全面存满了元素。

       while (hashArr[hashAdd] != -1)

       {

              if (hashArr[hashAdd] == value)

              {

                     return hashAdd;

              }

              //如果不相等,则往后进行探测

              ++hashAdd;

              //判断比过一圈,还没有没有找

              if (bj == hashAdd)

              {

                     break;

              }

              //处理的是,聚集在表的后面,最后一个也被填满了,但不是我们要找的值

              //从头又开始找

              if (hashAdd == hashLen)

              {

                     hashAdd = 0;

              }

       }

       return -1;

}


猜你喜欢

转载自blog.csdn.net/hnyjwang/article/details/81053687