Hashing in Data Structure
Hashing in Data Structure
Hashing
Another important and widely useful technique for implementing dictionaries Constant time per operation (on the average) Worst case time proportional to the size of the set for each operation (just like array and chain implementation)
Basic Idea
Use hash function to map keys into positions in a hash table Ideally If element e has key k and h is hash function, then e is stored in position h(k) of table To search for e, compute h(k) to locate position. If no element, dictionary does not contain e.
Example
Dictionary Student Records
Keys are ID numbers (951000 - 952000), no more than 100 students Hash function: h(k) = k-951000 maps ID into distinct table positions 0-1000 hash table array table[1001] ...
0 1 2 3
buckets
1000
Works for implementing dictionaries, but many applications have key ranges that are too large to have 1-1 mapping between buckets and keys! Example: Suppose key can take on values from 0 .. 65,535 (2 byte unsigned int) Expect 1,000 records at any given time Impractical to use hash table with 65,536 slots!
Hash Functions
If key range too large, use hash table with fewer buckets and a hash function which maps multiple keys to same bucket:
h(k1) = = h(k2): k1 and k2 have collision at slot
Difference has to do with whether collisions are stored outside the table (open hashing) or whether collisions result in storing one of the records at another slot in the table (closed hashing)
Closed Hashing
Associated with closed hashing is a rehash strategy: If we try to place x in bucket h(x) and find it occupied, find alternative location h1(x), h2(x), etc. Try each in order, if none empty table is full, h(x) is called home bucket Simplest rehash strategy is called linear hashing
hi(x) = (h(x) + i) % D
In general, our collision resolution strategy is to generate a sequence of hash table slots (probe sequence) that can hold the record; test each slot until find empty one (probing)
0 1 2 3 4 5 6 7
a c
Expected cost of hashing is a function of how full the table is: load factor = n/b It has been shown that average costs under linear hashing (probing) are:
Insertion: 1/2(1 + 1/(1 - )2) Deletion: 1/2(1 + 1/(1 - ))
Example
I
0 1 2 3 4 5 6 7 8 9 10
II
insert 1052 (h.b. 7)
0
1. What if next element has home bucket 0? h(k) = k%11 go to bucket 3 Same for elements with home bucket 1 or 2! Only a record with home position 3 will stay.
1 2 3 4
5
6 7 8 9 10
2. Similarly, records hashing to 7,8,9 will end up in 10 3. Only records hashing to 4 will end up in 4 (p=1/11); same for 5 and 6
Open Hashing
Each bucket in the hash table is the head of a linked list All elements that hash to a particular bucket are placed on that buckets linked list Records within a bucket can be ordered in several ways
by order of insertion, by key value order, or by frequency of access order
...
...
D-1
...
Analysis
Open hashing is most appropriate when the hash table is kept in main memory, implemented with a standard in-memory linked list
We hope that number of elements per bucket roughly equal in size, so that the lists will be short If there are n elements in set, then each bucket will have roughly n/D If we can estimate n and choose D to be roughly as large, then the average bucket will have only one or two members
Analysis Contd
Average time per dictionary operation: D buckets, n elements in dictionary average n/D elements per bucket insert, search, remove operation take O(1+n/D) time each If we can choose D to be about n, constant time Assuming each element is likely to be hashed to any bucket, running time constant, independent of n
Hashing Problem
Draw the 11 entry hashtable for hashing the keys 12, 44, 13, 88, 23, 94, 11, 39, 20 using the function (2i+5) mod 11, closed hashing, linear probing Pseudo-code for listing all identifiers in a hashtable in lexicographic order, using open hashing, the hash function h(x) = first character of x. What is the running time?