+Fri Apr 16 23:59:51 2004 Ben Pfaff <blp@gnu.org>
+
+ Contrary to what I'd always understood, there is an efficient
+ algorithm for deletion from a hash table populated via linear
+ probing. This change implements it.
+
+ * hash.c: (hsh_rehash) Probe in increasing order.
+ (hsh_probe) Ditto.
+ (locate_matching_entry) Ditto.
+ (hsh_delete) Use Knuth's Algorithm 6.4R for deletion.
+
Tue Apr 13 19:24:15 2004 Ben Pfaff <blp@gnu.org>
* moments.c (calc_moments): Adjust calculation of kurtosis to
for (i = 0; i < h->size; i++)
h->entries[i] = NULL;
for (table_p = begin; table_p < end; table_p++)
- {
- void **entry;
-
- if (*table_p == NULL)
- continue;
- entry = &h->entries[h->hash (*table_p, h->aux) & (h->size - 1)];
- while (*entry)
- if (--entry < h->entries)
- entry = &h->entries[h->size - 1];
- *entry = *table_p;
- }
+ if (*table_p != NULL)
+ {
+ void **entry = &h->entries[h->hash (*table_p, h->aux) & (h->size - 1)];
+ while (*entry != NULL)
+ if (++entry >= h->entries + h->size)
+ entry = h->entries;
+ *entry = *table_p;
+ }
free (begin);
}
{
if (!h->compare (*entry, target, h->aux))
return entry;
- if (--entry < h->entries)
- entry = &h->entries[h->size - 1];
+ if (++entry >= h->entries + h->size)
+ entry = h->entries;
}
h->used++;
return entry;
{
if (!h->compare (*entry, target, h->aux))
return entry;
- if (--entry < h->entries)
- entry = &h->entries[h->size - 1];
+ if (++entry >= h->entries + h->size)
+ entry = h->entries;
}
return NULL;
}
/* Deletes the entry in hash table H that matches TARGET.
Returns nonzero if an entry was deleted.
- Note: this function is very slow because it rehashes the
- entire table. Don't use this hash table implementation if
- deletion is a common operation. */
+ Uses Knuth's Algorithm 6.4R (Deletion with linear probing).
+ Because our load factor is at most 1/2, the average number of
+ moves that this algorithm makes should be at most 2 - ln 2 ~=
+ 1.65.
+
+ Not well tested. */
int
hsh_delete (struct hsh_table *h, const void *target)
{
void **entry = locate_matching_entry (h, target);
if (entry != NULL)
{
+ ptrdiff_t i;
+
+ h->used--;
if (h->free != NULL)
h->free (*entry, h->aux);
*entry = 0;
- hsh_rehash (h, h->size);
- return 1;
+
+ i = entry - h->entries;
+ for (;;)
+ {
+ unsigned r;
+ ptrdiff_t j = i;
+
+ do
+ {
+ if (--i < 0)
+ i = h->size - 1;
+ if (h->entries[i] == NULL)
+ return 1;
+
+ r = h->hash (h->entries[i], h->aux) & (h->size - 1);
+ }
+ while ((i <= r && r < j) || (r < j && j < i) || (j < i && i <= r));
+ h->entries[i] = h->entries[j];
+ }
}
else
return 0;