zoukankan      html  css  js  c++  java
  • php扩展开发实现一个简易的哈希表

    从一个简易的哈希表入手,会让你更好的理解php的哈希表,他们的本质是一样的,只是php的哈希表做了更多的功能扩展,php的哈希表是php语言的一个重要核心,大量的内核代码使用到哈希表。

      1 #include <string.h>
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 #define HASH_ADD 0
      5 #define HASH_UPDATE 1
      6 
      7 typedef unsigned long ulong;
      8 typedef unsigned int uint;
      9 
     10 typedef struct bucket {
     11     ulong h;                        //字符数组的key哈希值或者数字数组的key值
     12     uint nKeyLength;//字符数组的key长度,数字数组为0
     13     void *pData;//存储的数据
     14     struct bucket *pListNext;//在哈希表中的下一个元素
     15     struct bucket *pListLast;//在哈希表中的下一个元素
     16     struct bucket *pNext;//哈希值冲突时,同一哈希值链表的下一个元素
     17     struct bucket *pLast;//哈希值冲突时,同一哈希值链表的上一个元素
     18     const char *arKey;//字符数组的key值,数字数组为NULL
     19 } Bucket;
     20 
     21 typedef struct _hashtable {
     22     uint nTableSize;//哈希表的大小
     23     uint nTableMask;//用来计算哈希值所在当前哈希表的位置 
     24     uint nNumOfElements;//哈希表的元素数量
     25     ulong nNextFreeElement;//下一个自动插入的位置
     26     Bucket *pListHead;//哈希表的第一个元素
     27     Bucket *pListTail;//哈希表的最后一个元素
     28     Bucket **arBuckets;//哈希表存储数据的数组
     29 } HashTable;
     30 
     31 int hash_init(HashTable *ht, uint nSize);
     32 int hash_add(HashTable *ht, const char *arKey, uint nKeyLength, void *pData);
     33 int hash_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData);
     34 int _hash_add_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData, int flag);
     35 int hash_index_add(HashTable *ht, ulong h, void *pData);
     36 int hash_index_update(HashTable *ht, ulong h, void *pData);
     37 int hash_foreach(HashTable *ht);
     38 static int hash_resize_if_full(HashTable *ht);
     39 int hash_resize(HashTable *ht);
     40 char * hash_find(HashTable *ht,const char *arKey);
     41 char * hash_index_find(HashTable *ht,ulong h);
     42 
     43 int hash_init(HashTable *ht, uint nSize){
     44     uint i = 1;
     45 
     46     if (nSize >= 0x80000000) {
     47         /* prevent overflow */
     48         ht->nTableSize = 0x80000000;
     49     } else {
     50         while ((1U << i) < nSize) {
     51             i++;
     52         }
     53         ht->nTableSize = 1 << i;
     54     }
     55     ht->nTableMask = ht->nTableSize - 1;
     56     ht->nNumOfElements = 0;
     57     ht->nNextFreeElement = 0;
     58     ht->pListHead = NULL;
     59     ht->pListTail = NULL;
     60     ht->arBuckets = (Bucket **)calloc(ht->nTableSize,sizeof(Bucket *));  
     61     return 0;
     62 }
     63 
     64 static inline ulong hash_func(const char *arKey, uint nKeyLength)
     65 {
     66     register ulong hash = 5381;
     67 
     68     /* variant with the hash unrolled eight times */
     69     for (; nKeyLength >= 8; nKeyLength -= 8) {
     70         hash = ((hash << 5) + hash) + *arKey++;
     71         hash = ((hash << 5) + hash) + *arKey++;
     72         hash = ((hash << 5) + hash) + *arKey++;
     73         hash = ((hash << 5) + hash) + *arKey++;
     74         hash = ((hash << 5) + hash) + *arKey++;
     75         hash = ((hash << 5) + hash) + *arKey++;
     76         hash = ((hash << 5) + hash) + *arKey++;
     77         hash = ((hash << 5) + hash) + *arKey++;
     78     }
     79     switch (nKeyLength) {
     80         case 7: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
     81         case 6: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
     82         case 5: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
     83         case 4: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
     84         case 3: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
     85         case 2: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
     86         case 1: hash = ((hash << 5) + hash) + *arKey++; break;
     87         case 0: break;
     88     }
     89     return hash;
     90 }
     91 
     92 int hash_add(HashTable *ht, const char *arKey, uint nKeyLength, void *pData){
     93     return _hash_add_update(ht, arKey, nKeyLength, pData, HASH_ADD);
     94 }
     95 
     96 int hash_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData){
     97     return _hash_add_update(ht, arKey, nKeyLength, pData, HASH_UPDATE);
     98 }
     99 
    100 int _hash_add_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData, int flag){
    101     Bucket *p;
    102     ulong  h;
    103     ulong nIndex;
    104     h = hash_func(arKey, nKeyLength);
    105     nIndex = h & ht->nTableMask;
    106     p = ht->arBuckets[nIndex];
    107     while (p != NULL) {
    108         //printf("nIndex=>%d,arKey=>%s,p=>%s,%s\n",nIndex,arKey,p->arKey,p->pData);
    109         if (p->arKey == arKey){
    110             if(flag == HASH_ADD){
    111                 //已经存在同样的key
    112                 return -1; 
    113             }else{
    114                 p->pData = pData; 
    115                 return 0;
    116             }
    117         }
    118         p = p->pNext;
    119     }
    120     p = (Bucket *)malloc(sizeof(Bucket));
    121     p->h = h;
    122     p->nKeyLength = nKeyLength;
    123     p->pData = pData;
    124     p->pNext = ht->arBuckets[nIndex];
    125     p->pLast = NULL;
    126     if(p->pNext != NULL){
    127         p->pNext->pLast = p; 
    128     }
    129     p->arKey = arKey;
    130     ht->arBuckets[nIndex] = p;
    131     ht->nNumOfElements++;
    132     if(ht->pListHead == NULL){
    133         ht->pListHead = p; 
    134         p->pListNext = NULL;
    135         p->pListLast = NULL; 
    136         ht->pListTail = p;
    137     }else{
    138         p->pListLast = ht->pListTail;
    139         p->pListLast->pListNext = p;
    140         p->pListNext = NULL;
    141         ht->pListTail = p;
    142     }
    143     hash_resize_if_full(ht);
    144     return 0;
    145 }
    146 
    147 int hash_index_add(HashTable *ht, ulong h, void *pData){
    148     return _hash_index_add_update(ht,h,pData,HASH_ADD);
    149 }
    150 
    151 int hash_index_update(HashTable *ht, ulong h, void *pData){
    152     return _hash_index_add_update(ht,h,pData,HASH_UPDATE);
    153 }
    154 
    155 int hash_next_add(HashTable *ht,void *pData){
    156     ulong h = ht->nNextFreeElement;
    157     return _hash_index_add_update(ht,h,pData,HASH_ADD);
    158 }
    159 
    160 int _hash_index_add_update(HashTable *ht, ulong h,void *pData,int flag){
    161     Bucket *p;
    162     ulong nIndex;
    163     nIndex = h & ht->nTableMask;
    164     p = ht->arBuckets[nIndex];
    165     while (p != NULL) {
    166         if (p->arKey == NULL && p->nKeyLength == 0){
    167             if(flag == HASH_ADD){
    168                 //已经存在同样的key
    169                 return -1; 
    170             }else{
    171                 p->pData = pData; 
    172                 return 0;
    173             }
    174         }
    175         p = p->pNext;
    176     }
    177     p = (Bucket *)malloc(sizeof(Bucket));
    178     p->h = h;
    179     p->nKeyLength = 0;
    180     p->pData = pData;
    181     p->pNext = ht->arBuckets[nIndex];
    182     p->pLast = NULL;
    183     if(p->pNext != NULL){
    184         p->pNext->pLast = p; 
    185     }
    186     p->arKey = NULL;
    187     ht->arBuckets[nIndex] = p;
    188     ht->nNumOfElements++;
    189     if(h >= ht->nNextFreeElement){
    190         ht->nNextFreeElement = h + 1;
    191     }
    192     if(ht->pListHead == NULL){
    193         ht->pListHead = p; 
    194         p->pListNext = NULL;
    195         p->pListLast = NULL; 
    196         ht->pListTail = p;
    197     }else{
    198         p->pListLast = ht->pListTail;
    199         p->pListLast->pListNext = p;
    200         p->pListNext = NULL;
    201         ht->pListTail = p;
    202     }
    203     hash_resize_if_full(ht);
    204     return 0;
    205 }
    206 
    207 int hash_foreach(HashTable *ht){
    208     if(ht->pListHead == NULL){
    209         return ; 
    210     }
    211     Bucket *p;
    212     p = ht->pListHead;
    213     while(p != NULL){
    214         if(p->nKeyLength > 0){
    215             printf("h=>%ld,index=>%ld,%s=>%s\n",p->h,p->h & ht->nTableMask,p->arKey,p->pData); 
    216         }else{
    217             printf("h=>%ld,index=>%ld,%d=>%s\n",p->h,p->h & ht->nTableMask,p->h,p->pData); 
    218         }
    219         p=p->pListNext;
    220     }
    221 }
    222 
    223 static int hash_resize_if_full(HashTable *ht){
    224     //printf("if_null,num=>%d,size=>%d\n",ht->nNumOfElements,ht->nTableSize);
    225     if(ht->nNumOfElements >= ht->nTableSize){
    226         return hash_resize(ht);
    227     }
    228 }
    229 
    230 int hash_resize(HashTable *ht){
    231     printf("before resize:%d\n",ht->nTableSize);
    232     hash_foreach(ht);
    233     ht->nTableSize = ht->nTableSize << 1;
    234     ht->nTableMask = ht->nTableSize - 1;
    235     Bucket **t;
    236     t = realloc(ht->arBuckets,ht->nTableSize * sizeof(Bucket*));
    237     memset(t,0,ht->nTableSize * sizeof(Bucket *));
    238     ht->arBuckets = t;
    239     Bucket *p;
    240     ulong nIndex;
    241     for(p=ht->pListHead;p!=NULL;p=p->pListNext){
    242         nIndex = p->h & ht->nTableMask; 
    243         p->pNext = ht->arBuckets[nIndex];
    244         if(p->pNext != NULL){
    245             p->pNext->pLast = p; 
    246         }
    247         ht->arBuckets[nIndex] = p;
    248     }
    249     printf("after resize:%d\n",ht->nTableSize);
    250     hash_foreach(ht);
    251     return 0;
    252 }
    253 
    254 char * hash_find(HashTable *ht,const char *arKey){
    255     ulong h;
    256     int nKeyLength = strlen(arKey);
    257     h = hash_func(arKey, nKeyLength);
    258     ulong nIndex = h & ht->nTableMask;
    259     Bucket *p;
    260     for(p=ht->arBuckets[nIndex];p!=NULL;p=p->pNext){
    261         if(strcmp(p->arKey,arKey) == 0 && p->nKeyLength == nKeyLength){
    262             return p->pData; 
    263         } 
    264         printf("hash_find,arKey=>%s,nKeyLength=>%d,pData=>%s\n",p->arKey,p->nKeyLength,p->pData);
    265     }
    266     return NULL;
    267 }
    268 
    269 char * hash_index_find(HashTable *ht,ulong h){
    270     ulong nIndex = h & ht->nTableMask;
    271     Bucket *p;
    272     for(p=ht->arBuckets[nIndex];p!=NULL;p=p->pNext){
    273         if(p->nKeyLength == 0 && p->arKey == NULL){
    274             return p->pData;
    275         }
    276     }
    277 }
    278 
    279 int main(){
    280     HashTable *ht;
    281     ht = (HashTable *)malloc(sizeof(HashTable));
    282     hash_init(ht,1);//初始化哈希表,nTableSize=1
    283     char *arKey = "keya";
    284     int len = strlen(arKey);
    285     char *pData = "valuea";
    286     hash_add(ht,arKey,len,pData);//插入字符串数据
    287     arKey = "keyb";
    288     len = strlen(arKey);
    289     pData = "valueb";
    290     hash_add(ht,arKey,len,pData);
    291     arKey = "keyb";
    292     len = strlen(arKey);
    293     pData = "valueb";
    294     int ret = hash_add(ht,arKey,len,pData);//插入失败,key已经存在
    295     printf("ret=>%d\n",ret);
    296     char c;
    297     //char buffer[100];
    298     char *buffer;
    299     for(c='c';c<='z';c++){
    300         buffer = (char *)malloc(100);
    301         sprintf(buffer,"key%c",c); 
    302         arKey = buffer;
    303         len = strlen(arKey);
    304         buffer = (char *)malloc(100);
    305         sprintf(buffer,"value%c",c);
    306         pData = buffer;
    307         printf("%s,%s\n",arKey,pData);
    308         hash_add(ht,arKey,len,pData);//批量插入
    309     }
    310     for(c='A';c<='Z';c++){
    311         buffer = (char *)malloc(100);
    312         sprintf(buffer,"value%c",c);
    313         pData = buffer;
    314         hash_next_add(ht,pData);//使用数字数组,自动插入元素,不需要指定key
    315     }
    316     hash_index_add(ht,100,"index3");//使用数字数组,指定索引位置。
    317     hash_next_add(ht,"101");
    318     hash_next_add(ht,"102");
    319     hash_index_update(ht,100,"100 -> 102");//更新指定位置的值
    320     hash_foreach(ht);//遍历数组
    321     char *finda = hash_find(ht,"keya");//查找指定字符串key的值
    322     printf("finda=>%s\n",finda);
    323     char *findb = hash_index_find(ht,100);//查找指定索引的值
    324     printf("findb=>%s\n",findb);
    325 }
  • 相关阅读:
    linux常用脚本
    shell学习笔记
    Linux常用命令List
    Centos7部署Zabbix
    centos7安装nagios步骤
    nagios报错HTTP WARNING: HTTP/1.1 403 Forbidden解决方法
    U盘安装CentOS7
    Thread线程控制之sleep、join、setDaemon方法的用处
    EfficientDet框架详解 | 目前最高最快最小模型,可扩缩且高效的目标检测(附源码下载)
    ubuntu18.04 安装多版本cuda ,原来版本为9.0,在新增8.0
  • 原文地址:https://www.cnblogs.com/wuhen781/p/6184970.html
Copyright © 2011-2022 走看看