之前在大学学习数据结构的时候,学过数组和链表。数组的优点就是可以直接定位,速度快,但是缺点就是插入删除,效率就慢了很多。链表的可以快速的插入删除,但是不能直接定位,需要遍历才可以。他们使用在不同的场景下面。
有时候,又想快速的插入,又想快速的定位怎么办?这就需要把这两者优点糅合起来,哈希表就这么产生了。
哈希表的原理:一个动态数组,保存着元素的地址。通过一个公式,把元素的key(唯一),算出一个数值index。数组index位置就保存这个元素的指针。
这样存数据以及取数据,都可以通过这个公式,得到同一个位置。这个公式的目的,就是将key和数组的位置映射起来,当然没有任何的一个公式能够保证算出来的key和数组位置是一一对应的,也就是说,多个key算出来的index结果是同一个,这就是哈希冲突,稍后具体怎么解决它。
整个哈希表,最重要的就是这个映射公式,不但能够将字符串变成数值,而且能够平均分布。最常用的就是Times33算法
inline UINT CMyMap::HashKey(LPCTSTR key) const
{
UINT nHash = 5381;
while (*key)
nHash = (nHash << 5) + nHash + *key++;
return nHash;
}
5381是一个经验值,php就是使用这个值。
下面就是我写的代码。
1 #pragma once 2 #include "Bucket.h" 3 class HashTable 4 { 5 public: 6 HashTable(void); 7 ~HashTable(void); 8 static unsigned long hash_inline(const char* arKey,unsigned int nKeyLength); 9 bool add(const char* arKey,void* value); 10 void* getData(const char* arKey); 11 bool remove(const char* arKey); 12 bool resize(unsigned int nSize); 13 unsigned int nTableSize; 14 unsigned int nTableMask; 15 unsigned int nNumOfElements; 16 Bucket *pBucketCursor; 17 Bucket **arBuckets; 18 Bucket *pListHead; 19 Bucket *pListTail; 20 private: 21 void init(); 22 }; 23 #include "stdafx.h" 24 #include "HashTable.h" 25 #include <iostream> 26 #include <string.h> 27 using namespace std; 28 typedef unsigned long ulong; 29 typedef unsigned int uint; 30 31 HashTable::HashTable(void) 32 { 33 init(); 34 } 35 36 HashTable::~HashTable(void) 37 { 38 delete [] arBuckets; 39 } 40 41 ulong HashTable::hash_inline( const char* arKey,uint nKeyLength ) 42 { 43 register ulong hash=5381; 44 // for (; nKeyLength >= 8; nKeyLength -= 8) 45 // { 46 // const char *arKeyTemp=arKey; 47 // for(int i=0;i!=8;++i){ 48 // hash = ((hash << 5) + hash) + *arKey++; 49 // if(*arKey){ 50 // arKey=arKeyTemp; 51 // } 52 // } 53 // 54 // } 55 // switch (nKeyLength) 56 // { 57 // case 7: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */ 58 // case 6: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */ 59 // case 5: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */ 60 // case 4: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */ 61 // case 3: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */ 62 // case 2: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */ 63 // case 1: hash = ((hash << 5) + hash) + *arKey++; break; 64 // case 0: break; 65 // } 66 while (*arKey) 67 { 68 hash=(hash<<5)+hash+*arKey++; 69 } 70 return hash; 71 } 72 73 void HashTable::init() 74 { 75 nTableSize=8; 76 nTableMask=nTableSize-1; 77 arBuckets=new Bucket*[nTableSize](); 78 nNumOfElements=0; 79 } 80 81 bool HashTable::add(const char* arKey,void* value ) 82 { 83 ulong h=hash_inline(arKey,nTableSize); 84 uint nIndex=nTableMask&h; 85 Bucket *pbucket=arBuckets[nIndex]; 86 if (pbucket==NULL) 87 { 88 pbucket=new Bucket(arKey,value,h); 89 arBuckets[nIndex]=pbucket; 90 ++nNumOfElements; 91 if(nNumOfElements==1) 92 { 93 pListHead=pbucket; 94 pListTail=pbucket; 95 }else{ 96 pbucket->pListPre=pListTail; 97 pListTail->pListNext=pbucket; 98 pListTail=pbucket; 99 } 100 //cout<<"add key "<<pbucket->arKey<<endl; 101 }else{ 102 if(strcmp(pbucket->arKey,arKey)==0){ 103 //cout<<"key "<<arKey<<" is existed"<<endl; 104 return false; 105 }else{ 106 Bucket *pNewBucket=new Bucket(arKey,value,h); 107 while (pbucket->pNext!=NULL) 108 { 109 pbucket=pbucket->pNext; 110 } 111 pbucket->pNext=pNewBucket; 112 pNewBucket->pPre=pbucket; 113 pNewBucket->pListPre=pListTail; 114 pListTail->pListNext=pNewBucket; 115 pListTail=pNewBucket; 116 //cout<<"key "<<pbucket->arKey<<" next key is "<<pNewBucket->arKey<<endl; 117 ++nNumOfElements; 118 } 119 } 120 if(nNumOfElements>=nTableSize){ 121 resize(nTableSize*2); 122 } 123 return true; 124 } 125 126 bool HashTable::resize( unsigned int nSize ) 127 { 128 Bucket **arPBucketTemp=new Bucket*[nSize](); 129 Bucket *pListHeadTemp=NULL; 130 Bucket *pListTailTemp=NULL; 131 nTableSize=nSize; 132 nTableMask=nTableSize-1; 133 Bucket *pBucketCursorTemp=pListHead; 134 uint nNumOfElementsTemp=0; 135 //cout<<"--------------rehash-----------------"<<endl; 136 //cout<<"resize size:"<<nSize<<endl; 137 while (pBucketCursorTemp!=NULL) 138 { 139 /*//cout<<"resize pBucket key:"<<pBucketCursorTemp->arKey<<endl;*/ 140 Bucket *pbucket=pBucketCursorTemp; 141 pBucketCursorTemp=pBucketCursorTemp->pListNext; 142 ulong h=hash_inline(pbucket->arKey,nTableSize); 143 pbucket->nKeyLength=nTableSize; 144 pbucket->h=h; 145 uint nIndex=h&nTableMask; 146 Bucket *pbucketindex=arPBucketTemp[nIndex]; 147 if (pbucketindex==NULL) 148 { 149 arPBucketTemp[nIndex]=pbucket; 150 ++nNumOfElementsTemp; 151 if(nNumOfElementsTemp==1) 152 { 153 pListHeadTemp=pbucket; 154 pListTailTemp=pbucket; 155 pbucket->pListPre=NULL; 156 pbucket->pListNext=NULL; 157 pbucket->pNext=NULL; 158 pbucket->pPre=NULL; 159 }else{ 160 pbucket->pListPre=pListTailTemp; 161 pbucket->pListNext=NULL; 162 pbucket->pPre=NULL; 163 pbucket->pNext=NULL; 164 pListTailTemp->pListNext=pbucket; 165 pListTailTemp=pbucket; 166 } 167 }else{ 168 if(strcmp(pbucket->arKey,pbucketindex->arKey)==0){ 169 //cout<<"key "<<pbucket->arKey<<" is existed"<<endl; 170 return false; 171 }else{ 172 while (pbucketindex->pNext!=NULL) 173 { 174 pbucketindex=pbucketindex->pNext; 175 } 176 pbucketindex->pNext=pbucket; 177 pbucket->pPre=pbucketindex; 178 pbucket->pNext=NULL; 179 pbucket->pListPre=pListTailTemp; 180 pbucket->pListNext=NULL; 181 pListTailTemp->pListNext=pbucket; 182 pListTailTemp=pbucket; 183 /*//cout<<"key "<<pbucketindex->arKey<<" next key is "<<pbucketindex->pNext->arKey<<endl;*/ 184 ++nNumOfElementsTemp; 185 } 186 } 187 188 } 189 delete [] arBuckets; 190 arBuckets=arPBucketTemp; 191 pListTail=pListTailTemp; 192 pListHead=pListHeadTemp; 193 nNumOfElements=nNumOfElementsTemp; 194 //cout<<"--------------rehash end-----------------"<<endl; 195 return false; 196 } 197 198 void* HashTable::getData( const char* arKey ) 199 { 200 ulong h=hash_inline(arKey,nTableSize); 201 ulong nIndex=h&nTableMask; 202 Bucket *pbucket=arBuckets[nIndex]; 203 if(pbucket==NULL){ 204 return NULL; 205 }else{ 206 while (pbucket!=NULL) 207 { 208 if(strcmp(pbucket->arKey,arKey)==0){ 209 return pbucket->pData; 210 }else{ 211 pbucket=pbucket->pNext; 212 } 213 } 214 return NULL; 215 } 216 } 217 218 bool HashTable::remove( const char* arKey ) 219 { 220 ulong h=hash_inline(arKey,nTableSize); 221 ulong nIndex=h&nTableMask; 222 Bucket *pbucket=arBuckets[nIndex]; 223 if(pbucket==NULL){ 224 return false; 225 }else{ 226 while (pbucket!=NULL) 227 { 228 if(strcmp(pbucket->arKey,arKey)==0){ 229 if(pbucket==pListHead){ 230 pListHead=pbucket->pListNext; 231 if(pListHead!=NULL){ 232 pbucket->pListNext->pListPre=NULL; 233 } 234 } 235 if(pbucket==pListTail){ 236 pListTail=pbucket->pListPre; 237 if(pListTail!=NULL){ 238 pListTail->pListNext=NULL; 239 } 240 } 241 if(pbucket->pListPre!=NULL){ 242 pbucket->pListPre->pListNext=pbucket->pListNext; 243 } 244 if(pbucket->pListNext!=NULL){ 245 pbucket->pListNext->pListPre=pbucket->pListPre; 246 } 247 if(pbucket->pPre!=NULL){ 248 pbucket->pPre->pNext=pbucket->pNext; 249 }else{ 250 arBuckets[nIndex]=pbucket->pNext; 251 } 252 if(pbucket->pNext!=NULL){ 253 pbucket->pNext->pPre=pbucket->pPre; 254 } 255 --nNumOfElements; 256 delete pbucket; 257 return true; 258 }else{ 259 pbucket=pbucket->pNext; 260 } 261 } 262 return false; 263 } 264 }