% gcc -o chash chash.c > tcc chash.c % chash > h h(elp; q(uit; c(reate size; i(nsert x; D(elete x; d(isplay r(ehash Q(uadratic
Data File with Test Cases: chash.dat
i 89 i 18 i 49 i 58 i 69 d D 89 d c 10 Q d i 89 i 18 i 49 i 58 i 69 d r d
Closed Hashing: Linear Probing [110]
Linear Probing: if collision, then search for empty spot incrementally:
pos = hash(key,H_SIZE);
while (table[pos] != EMPTY_DATA) { /* collision */
pos = (++pos % H_SIZE);
}
position empty i 89 i 18 i 49 i 58 i 69 D 89
---------------------------------------------------
0 -1 -1 -1 49 49 49 49
1 -1 -1 -1 -1 58 58 58
2 -1 -1 -1 -1 -1 69 69
3 -1 -1 -1 -1 -1 -1 -1
4 -1 -1 -1 -1 -1 -1 -1
5 -1 -1 -1 -1 -1 -1 -1
6 -1 -1 -1 -1 -1 -1 -1
7 -1 -1 -1 -1 -1 -1 -1
8 -1 -1 18 18 18 18 18
9 -1 89 89 89 89 89 -2
Find: hash, start scanning for key or EMPTY_DATA
Delete: mark it as DEL_DATA (-2) so other keys can still be found
(How does this change the code above?)
Closed Hashing: Quadratic Probing [111]
Problem with Linear Probing: makes long sequential clusters
Quadratic Probing, if collision:
try next cell away (
)
then 4 cells away (
)
then 9 cells away (
)
Linear Probing:
position empty i 89 i 18 i 49 i 58 i 69
---------------------------------------------
0 -1 -1 -1 49 49 49
1 -1 -1 -1 -1 -1 -1
2 -1 -1 -1 -1 58 58
3 -1 -1 -1 -1 -1 69
4 -1 -1 -1 -1 -1 -1
5 -1 -1 -1 -1 -1 -1
6 -1 -1 -1 -1 -1 -1
7 -1 -1 -1 -1 -1 -1
8 -1 -1 18 18 18 18
9 -1 89 89 89 89 89
Closed Hashing: Rehashing [112]
Important: keep
If table fills up or clusters slow down performance: rehash.
Make a new table with ``doubled'' H_SIZE.
Insert old keys into new table.
Note: in general, H_SIZE should be prime.
position entry position entry
----------------------------------
0 -1 10 69
1 -1 11 -1
2 -1 12 -1
3 -1 13 -1
4 -1 14 -1
5 -1 15 -1
6 -1 16 -1
7 -1 17 -1
8 -1 18 58
9 49 19 18
Closed Hashing: chash.c [113]
#define EMPTY_DATA -1
#define DEL_DATA -2
#define NOT_FOUND -1
#define LINEAR_PROBING 0
#define QUADRATIC_PROBING 1
int probing = LINEAR_PROBING;
typedef int element_type;
typedef int INDEX;
struct hash_entry {
element_type element;
};
typedef INDEX position;
typedef struct hash_entry cell;
struct hash_tbl {
unsigned int table_size;
cell *the_cells;
};
typedef struct hash_tbl *HASH_TABLE;
HASH_TABLE create_hash_table(unsigned int table_size) {
HASH_TABLE H;
int i;
H = (HASH_TABLE) malloc(sizeof(struct hash_tbl));
if (H == NULL)
printf("Out of space!\n");
else {
H->table_size = table_size;
H->the_cells = (cell *) malloc(sizeof(cell)*H->table_size);
if (H->the_cells == NULL)
printf("Out of space!\n");
else {
for (i=0; i<H->table_size; i++)
H->the_cells[i].element = EMPTY_DATA;
}
}
return(H);
}
position find(element_type key, HASH_TABLE H) {
position i, current_pos;
i = 0;
current_pos = hash(key, H->table_size);
while ((H->the_cells[current_pos].element != EMPTY_DATA) &&
(H->the_cells[current_pos].element != key)) {
if (probing == LINEAR_PROBING)
current_pos = (++current_pos % H->table_size);
else { /* QUADRATIC PROBING */
current_pos += 2*(++i) - 1;
if (current_pos >= H->table_size)
current_pos -= H->table_size;
}
}
return(current_pos);
}
position insert(element_type key, HASH_TABLE H) {
position pos;
pos = find(key,H);
if ((H->the_cells[pos].element == EMPTY_DATA) ||
(H->the_cells[pos].element == DEL_DATA))
H->the_cells[pos].element = key;
else pos = NOT_FOUND;
return(pos);
}
position delete(element_type key, HASH_TABLE H) {
position pos;
pos = find(key,H);
if (H->the_cells[pos].element == key)
H->the_cells[pos].element = DEL_DATA;
else
pos = NOT_FOUND;
return(pos);
}
HASH_TABLE rehash(HASH_TABLE H) {
unsigned int i, old_size;
cell *old_cells;
old_cells = H->the_cells;
old_size = H->table_size;
H = create_hash_table(2*old_size);
for (i=0; i<old_size; i++)
if ((old_cells[i].element != EMPTY_DATA) &&
(old_cells[i].element != DEL_DATA))
insert(old_cells[i].element,H);
free(old_cells); /* Memory Leak ? */
return(H);
}