hashtable.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. // Simple hash table implemented in C.
  2. // From: https://github.com/benhoyt/ht
  3. #include "hashtable.h"
  4. #include <assert.h>
  5. #include <stdint.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #define INITIAL_CAPACITY 16 // must not be zero
  9. #define MULTIPLIER (37)
  10. ht* ht_create(void) {
  11. // Allocate space for hash table struct.
  12. ht* table = malloc(sizeof(ht));
  13. if (table == NULL) {
  14. return NULL;
  15. }
  16. table->length = 0;
  17. table->capacity = INITIAL_CAPACITY;
  18. // Allocate (zero'd) space for entry buckets.
  19. table->entries = calloc(table->capacity, sizeof(ht_entry));
  20. if (table->entries == NULL) {
  21. free(table); // error, free table before we return!
  22. return NULL;
  23. }
  24. return table;
  25. }
  26. void ht_destroy(ht* table) {
  27. // First free allocated keys.
  28. for (size_t i = 0; i < table->capacity; i++) {
  29. free((void*)table->entries[i].key);
  30. }
  31. // Then free entries array and table itself.
  32. free(table->entries);
  33. free(table);
  34. }
  35. #define FNV_OFFSET 14695981039346656037UL // FNV 偏移量
  36. #define FNV_PRIME 1099511628211UL // 64位的质数
  37. // Return 64-bit FNV-1a hash for key (NUL-terminated). See:
  38. // https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function
  39. static uint64_t hash_key_fnv(const char* key) {
  40. uint64_t hash = FNV_OFFSET;
  41. for (const char* p = key; *p; p++) {
  42. hash ^= (uint64_t)(unsigned char)(*p); // 异或
  43. hash *= FNV_PRIME;
  44. }
  45. return hash;
  46. }
  47. // 最简单的哈希函数,把字符的 ASCII 值相加
  48. uint64_t hash_key(const char* str) {
  49. uint64_t h = 0;
  50. for (int j=0; str[j]; j++)
  51. h = h + str[j];
  52. return h;
  53. }
  54. // 基于乘法的哈希函数:使用一个小的质数 MULTIPLIER 作为基数
  55. uint64_t hash_key_multi(const char* str) {
  56. uint64_t h = 0;
  57. for (int j=0; str[j]; j++)
  58. h = h * MULTIPLIER + str[j];
  59. return h;
  60. }
  61. void* ht_get(ht* table, const char* key) {
  62. // AND hash with capacity-1 to ensure it's within entries array.
  63. uint64_t hash = hash_key(key);
  64. size_t index = (size_t)(hash & (uint64_t)(table->capacity - 1));
  65. // Loop till we find an empty entry.
  66. while (table->entries[index].key != NULL) {
  67. if (strcmp(key, table->entries[index].key) == 0) {
  68. // Found key, return value.
  69. return table->entries[index].value;
  70. }
  71. // Key wasn't in this slot, move to next (linear probing).
  72. index++;
  73. if (index >= table->capacity) {
  74. // At end of entries array, wrap around.
  75. index = 0;
  76. }
  77. }
  78. return NULL;
  79. }
  80. // Internal function to set an entry (without expanding table).
  81. static const char* ht_set_entry(ht_entry* entries, size_t capacity,
  82. const char* key, void* value, size_t* plength) {
  83. // AND hash with capacity-1 to ensure it's within entries array.
  84. uint64_t hash = hash_key(key);
  85. size_t index = (size_t)(hash & (uint64_t)(capacity - 1));
  86. // Loop till we find an empty entry.
  87. while (entries[index].key != NULL) {
  88. if (strcmp(key, entries[index].key) == 0) {
  89. // Found key (it already exists), update value.
  90. entries[index].value = value;
  91. return entries[index].key;
  92. }
  93. // Key wasn't in this slot, move to next (linear probing).
  94. index++;
  95. if (index >= capacity) {
  96. // At end of entries array, wrap around.
  97. index = 0;
  98. }
  99. }
  100. // Didn't find key, allocate+copy if needed, then insert it.
  101. if (plength != NULL) {
  102. key = strdup(key);
  103. if (key == NULL) {
  104. return NULL;
  105. }
  106. (*plength)++;
  107. }
  108. entries[index].key = (char*)key;
  109. entries[index].value = value;
  110. return key;
  111. }
  112. // Expand hash table to twice its current size. Return true on success,
  113. // false if out of memory.
  114. static bool ht_expand(ht* table) {
  115. // Allocate new entries array.
  116. size_t new_capacity = table->capacity * 2;
  117. if (new_capacity < table->capacity) {
  118. return false; // overflow (capacity would be too big)
  119. }
  120. ht_entry* new_entries = calloc(new_capacity, sizeof(ht_entry));
  121. if (new_entries == NULL) {
  122. return false;
  123. }
  124. // Iterate entries, move all non-empty ones to new table's entries.
  125. for (size_t i = 0; i < table->capacity; i++) {
  126. ht_entry entry = table->entries[i];
  127. if (entry.key != NULL) {
  128. ht_set_entry(new_entries, new_capacity, entry.key,
  129. entry.value, NULL);
  130. }
  131. }
  132. // Free old entries array and update this table's details.
  133. free(table->entries);
  134. table->entries = new_entries;
  135. table->capacity = new_capacity;
  136. return true;
  137. }
  138. const char* ht_set(ht* table, const char* key, void* value) {
  139. assert(value != NULL);
  140. if (value == NULL) {
  141. return NULL;
  142. }
  143. // If length will exceed half of current capacity, expand it.
  144. if (table->length >= table->capacity / 2) {
  145. if (!ht_expand(table)) {
  146. return NULL;
  147. }
  148. }
  149. // Set entry and update length.
  150. return ht_set_entry(table->entries, table->capacity, key, value,
  151. &table->length);
  152. }
  153. size_t ht_length(ht* table) {
  154. return table->length;
  155. }
  156. hti ht_iterator(ht* table) {
  157. hti it;
  158. it._table = table;
  159. it._index = 0;
  160. return it;
  161. }
  162. bool ht_next(hti* it) {
  163. // Loop till we've hit end of entries array.
  164. ht* table = it->_table;
  165. while (it->_index < table->capacity) {
  166. size_t i = it->_index;
  167. it->_index++;
  168. if (table->entries[i].key != NULL) {
  169. // Found next non-empty item, update iterator key and value.
  170. ht_entry entry = table->entries[i];
  171. it->key = entry.key;
  172. it->value = entry.value;
  173. return true;
  174. }
  175. }
  176. return false;
  177. }