散列表
散列表的思想就是把关键值送给一个散列函数,产生出一个散列值,这个值平均分布在一个整数区域中
=>散列表的实现的细节
1 当数组足够大时可以直接寻址不需要散列函数,常数操作时间O(1)
但数据规模远大于散列表大小时,考虑到空间的局限性,需要散列函数使关键值均匀的分开
2 散列表的装载因子,也就是实际决定散列表运算时间的参数, 数据规模n 除与 散列表数组大小m 即 α = n/m
3 散列函数核心是采取一些措施尽可能地使关键字均地分开,
确保关键字的独立性 => 构造一个良好的散列函数
4 当关键值均匀地存储在散列链表里,花费常数操作时间+链表长度(数据规模n 除与 散列表数组大小m )= O(1)+n/m
如果散列函数弱爆了,几乎所有值都在一个链表里,那么花费线性时间(根据数据规模n)O(n)
5 散列表的大小为1001(选取素数,有助于更加均匀的分开关键值)
6 散列函数通过一系列相乘相加(基数为31),获取散列值(获取方式请看代码),最终值根据数组大小求模返回
7 通过链表解决碰撞(散列值相同情况),即散列表相当于一个数组,每个元素有一个链表
8 通过键 获取值的 一种散列表(键值对,使用动态分配内存)
1 #include <iostream> 2 #include <crtdbg.h> 3 using namespace std; 4 5 typedef int DataType; 6 7 struct Node 8 { 9 DataType data; 10 char *str; 11 Node * next; 12 }; 13 //可以直接使用一个结构体Node实现 14 //之所以分开是为了增加灵活性 15 struct hashNode 16 { 17 Node *node; 18 //hashNode *next; 19 }; 20 21 class Hash 22 { 23 private: 24 enum 25 { 26 MULTIPLIER = 31, //乘法散列基数(根据书里的经验 37 也可) 27 SIZE = 1001 //使用素数确定散列表大小,尽可能把关键吗均匀地分开 28 }; 29 hashNode *hashTable[SIZE];//散列表 30 int hashFn(const char* key);//散列函数 31 public: 32 Hash() 33 { 34 Init(); 35 } 36 ~Hash() 37 { 38 Delete(); 39 } 40 void Init(); 41 void Delete(); 42 bool Insert(const char* key, const DataType &data); 43 bool ExtractData(const char* key);//通过键删除该值 44 bool Find(const char* key, DataType &outData); 45 void Print()const; 46 47 }; 48 int Hash::hashFn(const char* key) 49 { 50 int hashVal = 0; 51 for (const char *p = key; *p != '\0'; ++p) 52 { 53 hashVal = MULTIPLIER*hashVal+ *p; 54 } 55 return hashVal%SIZE; 56 } 57 void Hash::Init() 58 { 59 for (int i=0; i<SIZE; ++i ) 60 { 61 hashTable[i] = NULL; 62 } 63 } 64 //释放内存 str、碰撞的node以及hashTable表头 65 void Hash::Delete() 66 { 67 for (int i=0; i<SIZE; ++i) 68 { 69 if (hashTable[i] !=NULL) 70 { 71 for (Node *p = hashTable[i]->node; p != NULL;) 72 { 73 Node *pTemp = p->next; 74 delete [] p->str; 75 delete p; 76 p = pTemp; 77 } 78 hashTable[i]->node = NULL; 79 delete hashTable[i]; 80 hashTable[i] = NULL; 81 } 82 } 83 } 84 //添加元素 85 bool Hash::Insert(const char* key, const DataType &data) 86 { 87 int index = hashFn(key); 88 if (hashTable[index] == NULL) 89 { 90 hashTable[index] = new hashNode; 91 hashTable[index]->node = new Node; 92 hashTable[index]->node->data = data; 93 hashTable[index]->node->str = new char[sizeof(key)+1]; 94 strcpy(hashTable[index]->node->str, key); 95 hashTable[index]->node->next = NULL; 96 } 97 else 98 { 99 Node* p = new Node; 100 p->data = data; 101 p->str = new char[sizeof(key)+1]; 102 strcpy(p->str, key); 103 p->next = hashTable[index]->node->next; 104 hashTable[index]->node->next = p; 105 } 106 return true; 107 } 108 //删除元素 109 bool Hash::ExtractData(const char* key) 110 { 111 int index = hashFn(key); 112 if (hashTable[index] == NULL) 113 { 114 return false; 115 } 116 else 117 { //考虑两种情况,hashTable表头 与 链表 118 if (strcmp(hashTable[index]->node->str, key) == 0) 119 { 120 Node *p = hashTable[index]->node->next; 121 Node *pTemp = hashTable[index]->node; 122 delete [] pTemp->str; 123 delete pTemp; 124 hashTable[index]->node = p; 125 126 return true; 127 } 128 else 129 { 130 Node *pPreNode = hashTable[index]->node; 131 for (Node *p=pPreNode->next; p !=NULL; ) 132 { 133 if (strcmp(p->str, key) == 0) 134 { 135 pPreNode->next = p->next; 136 delete [] p->str; 137 delete p; 138 p = NULL; 139 140 return true; 141 } 142 pPreNode = p; 143 p=p->next; 144 } 145 } 146 return false; 147 } 148 } 149 //通过键查找值,如果找到通过outData返回 150 bool Hash::Find(const char* key, DataType &outData) 151 { 152 int index = hashFn(key); 153 if (hashTable[index] == NULL) 154 { 155 return false; 156 } 157 else 158 { 159 for(Node *p = hashTable[index]->node;p !=NULL; p = p->next ) 160 { 161 if (strcmp(p->str, key) == 0) 162 { 163 outData = p->data; 164 return true; 165 } 166 } 167 } 168 return false; 169 } 170 void Hash::Print()const 171 { 172 for (int i=0; i<SIZE; ++i) 173 { 174 if (hashTable[i] != NULL) 175 { 176 for (Node *p = hashTable[i]->node; p!=NULL; p = p->next) 177 { 178 cout << p->str << "\t" << p->data << endl; 179 } 180 } 181 } 182 } 183 void main() 184 { 185 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); 186 187 Hash hash; 188 hash.Insert("tom", 15); 189 hash.Insert("bart", 17); 190 hash.Insert("shan", 17); 191 hash.Insert("eve", 16); 192 hash.Insert("jack", 21); 193 hash.Print(); 194 hash.ExtractData("jack"); 195 cout << endl; 196 hash.Print(); 197 198 cout << endl; 199 DataType data=0; 200 if (hash.Find("shan",data)) 201 { 202 cout << "shan: " << data << endl; 203 } 204 205 system("pause"); 206 }