首页 > 技术文章 > 数据结构哈希表(转)

hu-yewen 2016-06-05 13:18 原文

数据结构哈希表

参考代码如下:

 

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /*  
  2.     名称:哈希表   
  3.     语言:数据结构C语言版   
  4.     编译环境:VC++ 6.0  
  5.     日期: 2014-3-26   
  6. */  
  7.   
  8.   
  9. #include <stdio.h>  
  10. #include <malloc.h>  
  11. #include <windows.h>  
  12.   
  13.   
  14. #define NULLKEY 0   // 0为无记录标志   
  15. #define N 10        // 数据元素个数   
  16.   
  17. typedef int KeyType;// 设关键字域为整型   
  18.   
  19. typedef struct  
  20. {  
  21.     KeyType key;  
  22.     int ord;  
  23. }ElemType; // 数据元素类型   
  24.   
  25. // 开放定址哈希表的存储结构   
  26. int hashsize[]={11,19,29,37}; // 哈希表容量递增表,一个合适的素数序列   
  27. int m=0; // 哈希表表长,全局变量   
  28.   
  29. typedef struct  
  30. {  
  31.     ElemType *elem; // 数据元素存储基址,动态分配数组   
  32.     int count; // 当前数据元素个数   
  33.     int sizeindex; // hashsize[sizeindex]为当前容量   
  34. }HashTable;  
  35.   
  36. #define SUCCESS 1  
  37. #define UNSUCCESS 0  
  38. #define DUPLICATE -1  
  39.   
  40.   
  41. // 构造一个空的哈希表  
  42. int InitHashTable(HashTable *H)  
  43. {    
  44.     int i;  
  45.     (*H).count=0; // 当前元素个数为0   
  46.     (*H).sizeindex=0; // 初始存储容量为hashsize[0]   
  47.     m=hashsize[0];  
  48.     (*H).elem=(ElemType*)malloc(m*sizeof(ElemType));  
  49.     if(!(*H).elem)  
  50.         exit(0); // 存储分配失败   
  51.     for(i=0;i<m;i++)  
  52.         (*H).elem[i].key=NULLKEY; // 未填记录的标志   
  53.       
  54.     return 1;  
  55. }  
  56.   
  57. //  销毁哈希表H  
  58. void DestroyHashTable(HashTable *H)  
  59. {   
  60.     free((*H).elem);  
  61.     (*H).elem=NULL;  
  62.     (*H).count=0;  
  63.     (*H).sizeindex=0;  
  64. }  
  65.   
  66. // 一个简单的哈希函数(m为表长,全局变量)  
  67. unsigned Hash(KeyType K)  
  68. {   
  69.     return K%m;  
  70. }  
  71.   
  72. // 开放定址法处理冲突  
  73. void collision(int *p,int d) // 线性探测再散列   
  74. {    
  75.     *p=(*p+d)%m;  
  76. }  
  77.   
  78. // 在开放定址哈希表H中查找关键码为K的元素,若查找成功,以p指示待查数据   
  79. // 元素在表中位置,并返回SUCCESS;否则,以p指示插入位置,并返回UNSUCCESS   
  80. // c用以计冲突次数,其初值置零,供建表插入时参考。  
  81. int SearchHash(HashTable H,KeyType K,int *p,int *c)  
  82. {  
  83.     *p=Hash(K); // 求得哈希地址   
  84.     while(H.elem[*p].key!=NULLKEY&&!(K == H.elem[*p].key))  
  85.     {  
  86.         // 该位置中填有记录.并且关键字不相等   
  87.         (*c)++;  
  88.         if(*c<m)  
  89.             collision(p,*c); // 求得下一探查地址p   
  90.         else  
  91.             break;  
  92.     }  
  93.     if (K == H.elem[*p].key)  
  94.         return SUCCESS; // 查找成功,p返回待查数据元素位置   
  95.     else  
  96.         return UNSUCCESS; // 查找不成功(H.elem[p].key==NULLKEY),p返回的是插入位置   
  97. }  
  98.   
  99. int InsertHash(HashTable *,ElemType); // 对函数的声明   
  100.   
  101. // 重建哈希表  
  102. void RecreateHashTable(HashTable *H) // 重建哈希表   
  103. {   
  104.     int i,count=(*H).count;  
  105.     ElemType *p,*elem=(ElemType*)malloc(count*sizeof(ElemType));  
  106.     p=elem;  
  107.     printf("重建哈希表\n");  
  108.     for(i=0;i<m;i++) // 保存原有的数据到elem中   
  109.         if(((*H).elem+i)->key!=NULLKEY) // 该单元有数据   
  110.             *p++=*((*H).elem+i);  
  111.     (*H).count=0;  
  112.     (*H).sizeindex++; // 增大存储容量   
  113.     m=hashsize[(*H).sizeindex];  
  114.     p=(ElemType*)realloc((*H).elem,m*sizeof(ElemType));  
  115.     if(!p)  
  116.         exit(0); // 存储分配失败   
  117.     (*H).elem=p;  
  118.     for(i=0;i<m;i++)  
  119.         (*H).elem[i].key=NULLKEY; // 未填记录的标志(初始化)   
  120.     for(p=elem;p<elem+count;p++) // 将原有的数据按照新的表长插入到重建的哈希表中   
  121.         InsertHash(H,*p);  
  122. }  
  123.   
  124. // 查找不成功时插入数据元素e到开放定址哈希表H中,并返回1;   
  125. // 若冲突次数过大,则重建哈希表。  
  126. int InsertHash(HashTable *H,ElemType e)  
  127. {  
  128.     int c,p;  
  129.     c=0;  
  130.     if(SearchHash(*H,e.key,&p,&c)) // 表中已有与e有相同关键字的元素   
  131.         return DUPLICATE;  
  132.     else if(c<hashsize[(*H).sizeindex]/2) // 冲突次数c未达到上限,(c的阀值可调)   
  133.     {  
  134.         // 插入e   
  135.         (*H).elem[p]=e;  
  136.         ++(*H).count;  
  137.         return 1;  
  138.     }  
  139.     else  
  140.         RecreateHashTable(H); // 重建哈希表   
  141.       
  142.     return 0;  
  143. }  
  144.   
  145. // 按哈希地址的顺序遍历哈希表  
  146. void TraverseHash(HashTable H,void(*Vi)(int,ElemType))  
  147. {    
  148.     int i;  
  149.     printf("哈希地址0~%d\n",m-1);  
  150.     for(i=0;i<m;i++)  
  151.         if(H.elem[i].key!=NULLKEY) // 有数据   
  152.             Vi(i,H.elem[i]);  
  153. }  
  154.   
  155. // 在开放定址哈希表H中查找关键码为K的元素,若查找成功,以p指示待查数据   
  156. // 元素在表中位置,并返回SUCCESS;否则,返回UNSUCCESS   
  157. int Find(HashTable H,KeyType K,int *p)  
  158. {  
  159.     int c=0;  
  160.     *p=Hash(K); // 求得哈希地址   
  161.     while(H.elem[*p].key!=NULLKEY&&!(K == H.elem[*p].key))  
  162.     { // 该位置中填有记录.并且关键字不相等   
  163.         c++;  
  164.         if(c<m)  
  165.             collision(p,c); // 求得下一探查地址p   
  166.         else  
  167.             return UNSUCCESS; // 查找不成功(H.elem[p].key==NULLKEY)   
  168.     }  
  169.     if (K == H.elem[*p].key)  
  170.         return SUCCESS; // 查找成功,p返回待查数据元素位置   
  171.     else  
  172.         return UNSUCCESS; // 查找不成功(H.elem[p].key==NULLKEY)   
  173. }  
  174.   
  175.   
  176. void print(int p,ElemType r)  
  177. {  
  178.     printf("address=%d (%d,%d)\n",p,r.key,r.ord);  
  179. }  
  180.   
  181. int main()  
  182. {  
  183.     ElemType r[N] = {  
  184.         {17,1},{60,2},{29,3},{38,4},{1,5},  
  185.         {2,6},{3,7},{4,8},{60,9},{13,10}  
  186.     };  
  187.     HashTable h;  
  188.     int i, j, p;  
  189.     KeyType k;  
  190.       
  191.     InitHashTable(&h);  
  192.     for(i=0;i<N-1;i++)  
  193.     {  
  194.         // 插入前N-1个记录   
  195.         j=InsertHash(&h,r[i]);  
  196.         if(j==DUPLICATE)  
  197.             printf("表中已有关键字为%d的记录,无法再插入记录(%d,%d)\n",  
  198.                 r[i].key,r[i].key,r[i].ord);  
  199.     }  
  200.     printf("按哈希地址的顺序遍历哈希表:\n");  
  201.     TraverseHash(h,print);  
  202.     printf("请输入待查找记录的关键字: ");  
  203.     scanf("%d",&k);  
  204.     j=Find(h,k,&p);  
  205.     if(j==SUCCESS)  
  206.         print(p,h.elem[p]);  
  207.     else  
  208.         printf("没找到\n");  
  209.     j=InsertHash(&h,r[i]); // 插入第N个记录   
  210.     if(j==0) // 重建哈希表   
  211.         j=InsertHash(&h,r[i]); // 重建哈希表后重新插入第N个记录   
  212.     printf("按哈希地址的顺序遍历重建后的哈希表:\n");  
  213.     TraverseHash(h,print);  
  214.     printf("请输入待查找记录的关键字: ");  
  215.     scanf("%d",&k);  
  216.     j=Find(h,k,&p);  
  217.     if(j==SUCCESS)  
  218.         print(p,h.elem[p]);  
  219.     else  
  220.         printf("没找到\n");  
  221.     DestroyHashTable(&h);  
  222.       
  223.     system("pause");  
  224.     return 0;   
  225. }  
  226.   
  227. /*  
  228. 输出效果:  
  229.   
  230. 表中已有关键字为60的记录,无法再插入记录(60,9)  
  231. 按哈希地址的顺序遍历哈希表:  
  232. 哈希地址0~10  
  233. address=1 (1,5)  
  234. address=2 (2,6)  
  235. address=3 (3,7)  
  236. address=4 (4,8)  
  237. address=5 (60,2)  
  238. address=6 (17,1)  
  239. address=7 (29,3)  
  240. address=8 (38,4)  
  241. 请输入待查找记录的关键字: 17  
  242. address=6 (17,1)  
  243. 重建哈希表  
  244. 按哈希地址的顺序遍历重建后的哈希表:  
  245. 哈希地址0~18  
  246. address=0 (38,4)  
  247. address=1 (1,5)  
  248. address=2 (2,6)  
  249. address=3 (3,7)  
  250. address=4 (4,8)  
  251. address=6 (60,2)  
  252. address=10 (29,3)  
  253. address=13 (13,10)  
  254. address=17 (17,1)  
  255. 请输入待查找记录的关键字: 13  
  256. address=13 (13,10)  
  257. 请按任意键继续. . .  
  258.   
  259. */   


运行结果如下:

 

推荐阅读