哈希表的数据结构:
其实就是数组+链表:如图,
通过一个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)] = '