哈希表的數據結構:
其實就是數組+鏈表:如圖,
通過一個hash函數將key轉化成數組的下標,如果對應的下標在數組里面有數據,那么就沖突了,沖突了怎么辦呢,這個時候就把這個數組當成鏈表的頭結點,然后通過頭插法或者尾插法將新的節點數據插入到這個鏈表里面,理論上有hash表的size有多大,就有多少條鏈表,上圖就有16條,沖突得越多,鏈表的長度就越大。由於查找key的時候,通過key算出對應的數組下標,這個計算的過程是hash算法實現的,一般時間復雜度為O(1),所以得到下標的時間復雜度是O(1), 通過下標在數組中找數據的時間復雜度也是O(1), 所以哈希表的查找的時間復雜度在沒有沖突的情況下是O(1), 一旦有沖突,那么就要遍歷鏈表了。這個時候的時間復雜度就是根據鏈表的長度來決定的。
通過上面的數據結構,能夠定義出每個hash節點的數據結構
typedef struct HashNode{ char *key; int value; struct HashNode *nextNode; }HashNode;
而哈希表即上面HashNode的數組
typedef struct HashTable{ HashNode * hashNode[MAX_TABLE_SIZE]; int currentIndex; }HashTable;
好了,我們的數據結構構造出來了之后,接下來就是,初始化,添加,查找,刪除,等一系列操作hash表的騷操作了
初始化:
void InitHashTable(HashTable *hashTable) { memset(hashTable->hashNode, 0, sizeof(HashNode *) * MAX_TABLE_SIZE); hashTable->currentIndex = 0; }
插入函數:
//插入key value void Insert(HashTable *hashTable, char *key, int value) { int pos = HashFun(key) % MAX_TABLE_SIZE; HashNode * newNode = (HashNode *)malloc(sizeof(HashNode)); newNode->nextNode = NULL; newNode->key = (char *)malloc(sizeof(char) * (strlen(key) + 1)); strcpy(newNode->key, key); newNode->key[strlen(key)] = '\0'; newNode->value = value; HashNode *p = hashTable->hashNode[pos]; if (p == NULL) { //如果頭結點為空,說明沒有沖突 hashTable->hashNode[pos] = newNode; hashTable->currentIndex++; return; } //頭結點不為空,同時頭結點的key和輸入的key相同,覆蓋value if (strcmp(p->key, key) == 0) { p->value = value; return; } //頭結點不為空,沖突,插入到鏈表的第二個節點 HashNode *q = p->nextNode; newNode->nextNode = q; p->nextNode = newNode; }
獲取key對應的value
int * Get(HashTable *hashTable, char *key) { int pos = HashFun(key) % MAX_TABLE_SIZE; HashNode *p = hashTable->hashNode[pos]; if (p == NULL) { //如果頭結點為空,說明不存在這樣的key return NULL; } else { HashNode *q = p; while (q != NULL) { if(strcmp(q->key, key) == 0) { return &(q->value); } q = q->nextNode; } return NULL; } }
刪除對應的key
int Drop(HashTable *hashTable, char *key) { int pos = HashFun(key) % MAX_TABLE_SIZE; HashNode *p = hashTable->hashNode[pos]; if (p == NULL) { //如果頭結點為空,說明不存在這樣的key return 0; } else { if(strcmp(p->key, key) == 0) { //刪除的如果是頭結點 hashTable->hashNode[pos] = p->nextNode; free(p->key); free(p); return 1; } //刪除的不是頭結點的情況 HashNode *q = p->nextNode; HashNode * last = p; while (q != NULL) { if(strcmp(q->key, key) == 0) { last->nextNode = q->nextNode; free(q->key); free(q); return 1; } last = q; q = q->nextNode; } return 0; } }
打印所有數據
void PrintHashTable(HashTable *hashTable) { for(int i = 0; i < MAX_TABLE_SIZE; i++) { HashNode *head = hashTable->hashNode[i]; if (head == NULL) continue; printf("\n數組下標:%d======>", i); printf("(%s:%d)", head->key, head->value); head = head->nextNode; while(head) { printf("-->(%s:%d)", head->key, head->value); head = head->nextNode; } } }
釋放堆內存
void ClearHashTable(HashTable* hashTable) { for(int i = 0; i < MAX_TABLE_SIZE; i++) { HashNode *head = hashTable->hashNode[i]; while(head) { HashNode *temp = head->nextNode; free(head->key); free(head); head = temp; } } }
哈希規則
unsigned long HashFun(const char *key) { unsigned long hash = 0; int len = strlen(key); for (int i = 0; i < len; i++) { hash = hash * 33 + key[i]; } return hash; }
main函數測試
int main(void) { HashTable *hashTable = (HashTable *)malloc(sizeof(HashTable)); InitHashTable(hashTable); Insert(hashTable,"1234", 1); Insert(hashTable,"11234", 1); Insert(hashTable,"hello", 2); Insert(hashTable,"world", 3); Insert(hashTable,"hzp", 4); Insert(hashTable,"java", 5); Insert(hashTable,"b", 12); Insert(hashTable,"c", 12); Insert(hashTable,"c1", 12); Insert(hashTable,"c++", 18); Insert(hashTable,"html", 18); Insert(hashTable,"web", 18); Insert(hashTable,"python", 56); PrintHashTable(hashTable); int *data = Get(hashTable,"b"); printf("\n====%d=====\n", *data); Drop(hashTable, "python"); PrintHashTable(hashTable); ClearHashTable(hashTable); }
運行截圖:
附代碼:
#include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX_KEY_LEN 100 #define MAX_TABLE_SIZE 1000 typedef struct HashNode{ char *key; int value; struct HashNode *nextNode; }HashNode; typedef struct HashTable{ HashNode * hashNode[MAX_TABLE_SIZE]; int currentIndex; }HashTable; unsigned long HashFun(const char *key) { unsigned long hash = 0; int len = strlen(key); for (int i = 0; i < len; i++) { hash = hash * 33 + key[i]; } return hash; } //初始化 void InitHashTable(HashTable *hashTable) { memset(hashTable->hashNode, 0, sizeof(HashNode *) * MAX_TABLE_SIZE); hashTable->currentIndex = 0; } //插入key value void Insert(HashTable *hashTable, char *key, int value) { int pos = HashFun(key) % MAX_TABLE_SIZE; HashNode * newNode = (HashNode *)malloc(sizeof(HashNode)); newNode->nextNode = NULL; newNode->key = (char *)malloc(sizeof(char) * (strlen(key) + 1)); strcpy(newNode->key, key); newNode->key[strlen(key)] = '\0'; newNode->value = value; HashNode *p = hashTable->hashNode[pos]; if (p == NULL) { //如果頭結點為空,說明沒有沖突 hashTable->hashNode[pos] = newNode; hashTable->currentIndex++; return; } //頭結點不為空,同時頭結點的key和輸入的key相同,覆蓋value if (strcmp(p->key, key) == 0) { p->value = value; return; } //頭結點不為空,沖突,插入到鏈表的第二個節點 HashNode *q = p->nextNode; newNode->nextNode = q; p->nextNode = newNode; } int * Get(HashTable *hashTable, char *key) { int pos = HashFun(key) % MAX_TABLE_SIZE; HashNode *p = hashTable->hashNode[pos]; if (p == NULL) { //如果頭結點為空,說明不存在這樣的key return NULL; } else { HashNode *q = p; while (q != NULL) { if(strcmp(q->key, key) == 0) { return &(q->value); } q = q->nextNode; } return NULL; } } int Drop(HashTable *hashTable, char *key) { int pos = HashFun(key) % MAX_TABLE_SIZE; HashNode *p = hashTable->hashNode[pos]; if (p == NULL) { //如果頭結點為空,說明不存在這樣的key return 0; } else { if(strcmp(p->key, key) == 0) { //刪除的如果是頭結點 hashTable->hashNode[pos] = p->nextNode; free(p->key); free(p); return 1; } //刪除的不是頭結點的情況 HashNode *q = p->nextNode; HashNode * last = p; while (q != NULL) { if(strcmp(q->key, key) == 0) { last->nextNode = q->nextNode; free(q->key); free(q); return 1; } last = q; q = q->nextNode; } return 0; } } void ClearHashTable(HashTable* hashTable) { for(int i = 0; i < MAX_TABLE_SIZE; i++) { HashNode *head = hashTable->hashNode[i]; while(head) { HashNode *temp = head->nextNode; free(head->key); free(head); head = temp; } } } void PrintHashTable(HashTable *hashTable) { for(int i = 0; i < MAX_TABLE_SIZE; i++) { HashNode *head = hashTable->hashNode[i]; if (head == NULL) continue; printf("\nindex:%d======>", i); printf("(%s:%d)", head->key, head->value); head = head->nextNode; while(head) { printf("-->(%s:%d)", head->key, head->value); head = head->nextNode; } } } int main(void) { HashTable *hashTable = (HashTable *)malloc(sizeof(HashTable)); InitHashTable(hashTable); Insert(hashTable,"1234", 1); Insert(hashTable,"11234", 1); Insert(hashTable,"hello", 2); Insert(hashTable,"world", 3); Insert(hashTable,"hzp", 4); Insert(hashTable,"java", 5); Insert(hashTable,"b", 12); Insert(hashTable,"c", 12); Insert(hashTable,"c1", 12); Insert(hashTable,"c++", 18); Insert(hashTable,"html", 18); Insert(hashTable,"web", 18); Insert(hashTable,"python", 56); PrintHashTable(hashTable); int *data = Get(hashTable,"b"); printf("\n====%d=====\n", *data); Drop(hashTable, "python"); PrintHashTable(hashTable); ClearHashTable(hashTable); }