Skip to content

Commit bf837df

Browse files
committed
Hash-based Map: fix edge case of filling table with DELETED
1 parent 0a0529a commit bf837df

File tree

2 files changed

+27
-2
lines changed

2 files changed

+27
-2
lines changed

modules/UsingHashTable/ADTMap.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ struct map {
3838
MapNode array; // Ο πίνακας που θα χρησιμοποιήσουμε για το map (remember, φτιάχνουμε ένα hash table)
3939
int capacity; // Πόσο χώρο έχουμε δεσμεύσει.
4040
int size; // Πόσα στοιχεία έχουμε προσθέσει
41+
int deleted; // Πόσα κελιά είναι DELETED
4142
CompareFunc compare; // Συνάρτηση για σύγκριση δεικτών, που πρέπει να δίνεται απο τον χρήστη
4243
HashFunc hash_function; // Συνάρτηση για να παίρνουμε το hash code του κάθε αντικειμένου.
4344
DestroyFunc destroy_key; // Συναρτήσεις που καλούνται όταν διαγράφουμε έναν κόμβο απο το map.
@@ -56,6 +57,7 @@ Map map_create(CompareFunc compare, DestroyFunc destroy_key, DestroyFunc destroy
5657
map->array[i].state = EMPTY;
5758

5859
map->size = 0;
60+
map->deleted = 0;
5961
map->compare = compare;
6062
map->destroy_key = destroy_key;
6163
map->destroy_value = destroy_value;
@@ -141,15 +143,19 @@ void map_insert(Map map, Pointer key, Pointer value) {
141143
} else {
142144
// Νέο στοιχείο, αυξάνουμε τα συνολικά στοιχεία του map
143145
map->size++;
146+
147+
if (node->state == DELETED) // αν βρήκαμε DELETED, θα αλλάξει σε OCCUPIED
148+
map->deleted--;
144149
}
145150

146151
// Προσθήκη τιμών στον κόμβο
147152
node->state = OCCUPIED;
148153
node->key = key;
149154
node->value = value;
150155

151-
// Αν με την νέα εισαγωγή ξεπερνάμε το μέγιστο load factor, πρέπει να κάνουμε rehash
152-
float load_factor = (float)map->size / map->capacity;
156+
// Αν με την νέα εισαγωγή ξεπερνάμε το μέγιστο load factor, πρέπει να κάνουμε rehash.
157+
// Στο load factor μετράμε και τα DELETED, γιατί και αυτά επηρρεάζουν τις αναζητήσεις.
158+
float load_factor = (float)(map->size + map->deleted) / map->capacity;
153159
if (load_factor > MAX_LOAD_FACTOR)
154160
rehash(map);
155161
}
@@ -168,6 +174,7 @@ bool map_remove(Map map, Pointer key) {
168174

169175
// θέτουμε ως "deleted", ώστε να μην διακόπτεται η αναζήτηση, αλλά ταυτόχρονα να γίνεται ομαλά η εισαγωγή
170176
node->state = DELETED;
177+
map->deleted++;
171178
map->size--;
172179

173180
return true;

tests/ADTMap_test.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,24 @@ void test_remove(void) {
160160
int key1 = 100;
161161
TEST_ASSERT(!map_remove(map, &key1));
162162
map_destroy(map);
163+
164+
165+
// Σειριακή εισαγωγή στοιχείων και αμέσως διαγραφή. Αυτό σε έναν πίνακα κατακερματισμού
166+
// μπορεί να προκαλέσει όλα τα κελιά να είναι μαρκαρισμένα ως DELETED.
167+
map = map_create(compare_ints, free, free);
168+
map_set_hash_function(map, hash_int);
169+
170+
for (int i = 0; i < N; i++) {
171+
key_array[i] = create_int(i);
172+
value_array[i] = create_int(i);
173+
174+
map_insert(map, key_array[i], value_array[i]);
175+
map_remove(map, key_array[i]);
176+
177+
TEST_ASSERT(map_size(map) == 0);
178+
}
179+
map_destroy(map);
180+
163181
free(key_array);
164182
free(value_array);
165183
}

0 commit comments

Comments
 (0)