Hash Table - Hash Table - Hash Storage - Code Implementation

Let's first understand the basic idea of ​​Hash:

suppose the number of objects to be stored is num, then we use len memory units to store them (len>=num); take the keyword of each object ki as an independent variable, use A function h(ki) is used to map out the memory address of ki, that is, the subscript of ki, and it is enough to store all the elements of the ki object in this address. This is the basic idea of ​​Hash.
Why does Hash think so? In other words, why use a function to map out their address locations?
This is a good question. Understand the problem, Hash is no longer a problem. Now I will answer this question for you in a simple and easy to understand way.
Now I want to store 4 elements 13 7 14 11

Obviously, we can use an array to store it. That is: a[1] = 13; a[2] = 7; a[3] = 14; a[4] = 11;

Of course, we can also use Hash to store. A simple Hash store is given below:

Let's determine that function first. We just use h(ki) = ki%5; (this function does not need to be tangled, our purpose now is to understand why there is such a function).

For the first element h(13) = 13%5 = 3; that is, the subscript of 13 is 3; that is, Hash[3] = 13;

For the second element h(7) = 7 % 5 = 2; that is, the subscript of 7 is 2; that is, Hash[2] = 7;

Similarly, Hash[4] = 14; Hash[1] = 11;

Well, the save is now saved. However, this does not reflect the beauty of Hash, nor does it answer the question just now. Let's unravel its mystery.

Now I want you to find out if the element 11 exists. What would you do? Of course, for arrays, that's pretty simple, a for loop will do.

That is to say, we have to find 4 times.

Let's use Hash to find it.

首先,我们将要找的元素11代入刚才的函数中来映射出它所在的地址单元。也就是h(11) = 11%5 = 1 了。下面我们来比较一下Hash[1]?=11, 这个问题就很简单了。也就是说我们就找了1次。这个就是Hash的妙处了。至此,刚才的问题也就得到了解答。至此,你也就彻底的明白了Hash了。



Hash冲突的处理

已知一组关键字为(26,36,41,38,44,15,68,12,06,51),用除余法构造散列函数,用线性探查法解决冲突构造这组关键字的散列表。

  

解答:

为了减少冲突,通常令装填因子α     

由除余法的散列函数计算出的上述关键字序列的散列地址为(0,10,2,12,5,2,3,12,6,12)。

前5个关键字插入时,其相应的地址均为开放地址,故将它们直接插入T[0],T[10),T[2],T[12]和T[5]中。

当插入第6个关键字15时,其散列地址2(即h(15)=15%13=2)已被关键字41(15和41互为同义词)占用。

故探查h1=(2+1)%13=3,此地址开放,所以将15放入T[3]中。

当插入第7个关键字68时,其散列地址3已被非同义词15先占用,故将其插入到T[4]中。

当插入第8个关键字12时,散列地址12已被同义词38占用,故探查hl=(12+1)%13=0,而T[0]亦被26占用,再探查h2=(12+2)%13=1,此地址开放,可将12插入其中。

类似地,第9个关键字06直接插入T[6]中;而最后一个关键字51插人时,因探查的地址12,0,1,…,6均非空,故51插入T[7]中。


散列技术既是一种存储方法,也是一种查找方法。

哈希查找是一种秒杀查找,时间复杂度为O(1),只要用key通过哈希函数就直接计算出key的存储位置。

散列技术是在记录关键字的存储位置和关键字本身建立了一种对应关系-------就是一种函数关系f

     比如:f(key)=a*key+b (a,b为常数) ,存储的数据是key,存储的位置是f(key),这个f(key)可以是某个数组的下标。

散列函数:这种函数关系如何确定呢?---2个原则:计算简单(计算复杂导致效率低下)、散列地址分布均匀(有效利用空间,同时通过减小冲突而减小耗费时间)

                       几种散列函数参考:

                      (1)直接定址法:f(key)=a*key+b  (a,b为常数)

                      (2)数字分析法 :用于数字较长且有特点。比如类似电话号码处理。11位手机号码-数字比较有特点--基本就最后四位是最经常变化的(前三位是运营商,中间四位是地区,后四位是用户编号)。

                      (3)平方取中法:比如存储关键字1234,平方为1522756,再抽取中间三位227作为存储地址。

                      (4)折叠法:比如存储9876543210,可将其分为四组987|654|321|0,四组求和987+654+3210=962作为存储地址

                      (5)取余数法:f(key)=key%p  (p≤m,m为散列表的长度)

                      (6)随机数法:f(key)=random(key)

散列冲突:当存储两个不同的数据时,通过散列函数却计算得到相同的存储位置。f(key1)=f(key2)----散列冲突

解决散列冲突:散列冲突是很糟糕的事情,必须要解决,否则数据无法正常存储和查找。

                   解决方法参考如下:

                 (1)开放定址法---线性探测 :fi(key)=(f(key)+di)%m (di=1 ,2 , 3,....)

                 (2)开放定址法---二次探测:fi(key)=(f(key)+di)%m (di=1 ^2,-1^2,2^2,-2^2 , 3^2,....)

                 (3)开放定址法---随机探测:fi(key)=(f(key)+di)%m (di是随机数)

                 (4)再散列函数:就是事先准备多个散列函数,当冲突时更换散列函数再计算。

                 (5)链地址法:

                 (4)公共溢出区法:建立多个散列表。其中一个为基本表,另外为溢出表。当冲突时,将数据存储到溢出表中。

创建哈希表思路:

             1、确定哈希表的长度,根据长度建立哈希存储空间(比如定义数组)

             2、确定散列函数。

             3、有了空间可散列函数就要开始存数据了,取数据的关键字key,计算key的存储地址

             4、如果有冲突就转到相应的冲突解决方法。

哈希查找思路:

           1、给定key值和查找的对象存储空间(比如给以数组或链表)

            2、通过散列函数计算key值对应的存储地址

           3、同时判别是否冲突,冲突则通过更换地址继续查找,若找完散列表所有地址也没有找到key,则返回查找失败。


散列实现:存储方法:取余数法      +      解决散列冲突:开放定址法---线性探测法

  1. #include"stdio.h"  
  2. #include"assert.h"  
  3. #include"math.h"  
  4. #include"stdlib.h"  
  5.   
  6. #define SUCCESS 1  
  7. #define UNSUCCESS 0  
  8. #define HASHBIAOSIZE  15 //决定散列表大小的参数  
  9.   
  10. #define M 12 //  
  11. #define NULLKEY -65535  
  12. //-----------------------------------------------------------------------------------//  
  13. typedef struct  HashTable{  
  14.     int* element;//  
  15.         int count;//  
  16. }HashTable;  
  17.   
  18. int m=0;  
  19. void InitHashTable(HashTable *H);  
  20. void InsertHashKey(HashTable* H,int key);  
  21. int  Hash_f(int key);  
  22. int SearchHashKey(HashTable* H,int key);  
  23. //-----------------------------------------------------------------------------------//  
  24.   
  25.   
  26. void main(){  
  27.     int a[]={1,12,5,4,6,8,7,45,21,13,18,35};  
  28.     HashTable H;  
  29.     InitHashTable(&H);  
  30.     for(int i=0;i<M;i++){  
  31.         InsertHashKey(&H,a[i]);}  
  32.     for(int j=0;j<M;j++){  
  33.     if(-1==SearchHashKey(&H,a[j]))  printf("没查找到\n");  
  34.     else printf("查找元素存储的标号 %d\n",SearchHashKey(&H,a[j]));  
  35.     }  
  36.   
  37. }  
  38.   
  39.   
  40.   
  41. //-----------------------------------------------------------------------------------//  
  42. void InitHashTable(HashTable *H)  
  43. {  
  44.      m=HASHBIAOSIZE;     
  45.      H->element=(int*)malloc(m*sizeof(int));  
  46.      H->count=HASHBIAOSIZE;  
  47.      
  48.     for(int i=0;i<m;i++){  
  49.         H->element[i]=NULLKEY;  
  50.     }  
  51. }  
  52. //-----------------------------------------------------------------------------------//  
  53. //存储元素  
  54. //这里采用取余数法  
  55. void InsertHashKey(HashTable* H,int key){  
  56.        
  57.     int addr=Hash_f(key);  
  58.     while(H->element[addr]!=NULLKEY){ //冲突了  
  59.        addr=(addr+1)%M;//解决冲突  
  60.     }  
  61.     H->element[addr]=key;  
  62.   
  63. }  
  64. //-----------------------------------------------------------------------------------//  
  65. //查找元素  
  66. int SearchHashKey(HashTable* H,int key){  
  67.     
  68.     int addr=Hash_f(key);  
  69.     while(H->element[addr]!=key){  
  70.   
  71.     addr=(addr+1)%M;  
  72.     if(H->element[addr]==NULLKEY || addr==Hash_f(key)){return -1;}//UNSUCCESS  
  73.     }  
  74.     return addr;//查找成功,返回存储位置  
  75. }  
  76. //-----------------------------------------------------------------------------------//  
  77. int  Hash_f(int key){  
  78.     return key%M;  
  79. }  
  80. //-----------------------------------------------------------------------------------//  

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325733576&siteId=291194637