Extendible hashing visualizer

Extendible hashing grows a hash table one bucket at a time: a full bucket splits on one more bit of the hash, and the directory that points to the buckets doubles only when it has to. Paste the keys from your exercise, pick your textbook's conventions, and step through every split.

Global depth
3
Buckets
7
Keys
12
Directory uses
Bucket size
Keys are
Hash width
On delete
12 of 12
Directory (8 entries, global depth 3) and buckets (local depth in brackets)
000 001 010 011 100 101 110 111A [3] 16 00010000 B [3] 25 00011001 9 00001001D [3] 18 00010010 2 00000010C [2] 7 00000111 11 00001011G [3] 4 00000100 28 00011100E [3] 13 00001101 21 00010101F [3] 30 00011110

Bits in bold are the ones each bucket's keys share (its local depth), counted from the right.

16 goes to directory entry 000, bucket A, which has room.

Table
Global depth
3
Directory entries
8
Buckets
7
Bucket space used
85.7%
  1. 113 goes to the only directory entry, bucket A, which has room.
  2. 24 goes to the only directory entry, bucket A, which has room.
  3. 3The only directory entry points to bucket A, which is full (2 of 2).
  4. Its local depth already equals the global depth, so the directory doubles from 1 to 2 entries; each new entry points where its pair did.
  5. Split A on bit 1 from the right: keys with a 1 there move to new bucket B (13). Both now have local depth 1.
  6. 30 goes to directory entry 0, bucket A, which has room.
  7. 421 goes to directory entry 1, bucket B, which has room.
  8. 5Entry 1 points to bucket B, which is full (2 of 2).
  9. Its local depth already equals the global depth, so the directory doubles from 2 to 4 entries; each new entry points where its pair did.
  10. Split B on bit 2 from the right: keys with a 1 there move to new bucket C (none). Both now have local depth 2.
  11. 7 goes to directory entry 11, bucket C, which has room.
  12. 6Entry 10 points to bucket A, which is full (2 of 2).
  13. Split A on bit 2 from the right: keys with a 1 there move to new bucket D (30). Both now have local depth 2.
  14. 18 goes to directory entry 10, bucket D, which has room.
  15. 7Entry 01 points to bucket B, which is full (2 of 2).
  16. Its local depth already equals the global depth, so the directory doubles from 4 to 8 entries; each new entry points where its pair did.
  17. Split B on bit 3 from the right: keys with a 1 there move to new bucket E (13, 21). Both now have local depth 3.
  18. 25 goes to directory entry 001, bucket B, which has room.
  19. 8Entry 010 points to bucket D, which is full (2 of 2).
  20. Split D on bit 3 from the right: keys with a 1 there move to new bucket F (30). Both now have local depth 3.
  21. 2 goes to directory entry 010, bucket D, which has room.
  22. 911 goes to directory entry 011, bucket C, which has room.
  23. 109 goes to directory entry 001, bucket B, which has room.
  24. 1128 goes to directory entry 100, bucket A, which has room.
  25. 12Entry 000 points to bucket A, which is full (2 of 2).
  26. Split A on bit 3 from the right: keys with a 1 there move to new bucket G (4, 28). Both now have local depth 3.
  27. 16 goes to directory entry 000, bucket A, which has room.
Answer, step by step
#OperationHash bitsWhat happenedGlobalBuckets after
1 insert 13 00001101 placed 0 A(0): 13
2 insert 4 00000100 placed 0 A(0): 13 4
3 insert 30 00011110 directory doubles, A splits to B, placed 1 A(1): 4 30 B(1): 13
4 insert 21 00010101 placed 1 A(1): 4 30 B(1): 13 21
5 insert 7 00000111 directory doubles, B splits to C, placed 2 A(1): 4 30 B(2): 13 21 C(2): 7
6 insert 18 00010010 A splits to D, placed 2 A(2): 4 B(2): 13 21 D(2): 30 18 C(2): 7
7 insert 25 00011001 directory doubles, B splits to E, placed 3 A(2): 4 B(3): 25 D(2): 30 18 C(2): 7 E(3): 13 21
8 insert 2 00000010 D splits to F, placed 3 A(2): 4 B(3): 25 D(3): 18 2 C(2): 7 E(3): 13 21 F(3): 30
9 insert 11 00001011 placed 3 A(2): 4 B(3): 25 D(3): 18 2 C(2): 7 11 E(3): 13 21 F(3): 30
10 insert 9 00001001 placed 3 A(2): 4 B(3): 25 9 D(3): 18 2 C(2): 7 11 E(3): 13 21 F(3): 30
11 insert 28 00011100 placed 3 A(2): 4 28 B(3): 25 9 D(3): 18 2 C(2): 7 11 E(3): 13 21 F(3): 30
12 insert 16 00010000 A splits to G, placed 3 A(3): 16 B(3): 25 9 D(3): 18 2 C(2): 7 11 G(3): 4 28 E(3): 13 21 F(3): 30

How to use the simulator

Type or paste the keys from your exercise, separated by commas or spaces, and choose the conventions your course uses: which bits of the hash index the directory, how many keys a bucket holds, and how wide the hash is. "Run all" inserts every key; "Start step by step" lets you go one key at a time with Next and Back. The answer table under the drawing lists each operation, what it caused and every bucket afterwards, and "Copy answer" puts it on the clipboard as plain text.

  • Decimal keys are hashed by taking the key modulo 2width, the usual convention in exercises, so 13 with an 8-bit hash is 00001101. To use the hash values from your exercise directly, switch to "Hash bits" and type bit strings such as 0110.
  • Prefix a key with x to delete it, for example "x13". The merge rule decides whether buckets combine again.
  • "Copy link" gives an address that reopens this exact exercise, for a bookmark or to send to someone.

What is extendible hashing?

Extendible hashing is a way of storing a hash index on disk that grows smoothly as keys are added. Keys live in fixed-size buckets, usually one disk page each. A directory of 2d pointers sits in front of them, and a key's bucket is found by taking d bits of its hash, the global depth, and following that directory entry. A lookup therefore costs one directory access and one bucket access, however large the table gets.

Buckets do not each need all d bits. A bucket's local depth l is the number of bits its keys are known to share, and 2d − l directory entries point to it. Static hashing has to rehash every key when the table outgrows its buckets. Extendible hashing never does: when one bucket overflows, only that bucket is split.

Insert, split and double

To insert a key, find its bucket through the directory. If the bucket has room, the key goes in. If it is full:

  1. If the bucket's local depth is less than the global depth, several directory entries point to it. Split it: create a new bucket, raise both local depths by one, move the keys whose next bit is 1 to the new bucket, and repoint half of the directory entries to it.
  2. If the local depth equals the global depth, only one entry points to it, so there is nothing to divide. First double the directory, with each new entry copying the pointer of the entry it was made from, then split as above.
  3. Try the insert again; if every key landed on the same side, the bucket may still be full and the process repeats.

Inserting the page's default keys, 13, 4, 30, 21, 7, 18, 25, 2, 11, 9, 28, 16, into buckets of two with the last bits of an 8-bit hash takes 6 splits, 3 of which double the directory, and ends with global depth 3 and 7 buckets:

KeyHash bitsGlobal depth afterBuckets afterWhat happened
130000110101placed
40000010001placed
300001111012directory doubles; split A on bit 1 from the right
210001010112placed
70000011123directory doubles; split B on bit 2 from the right
180001001024split A on bit 2 from the right
250001100135directory doubles; split B on bit 3 from the right
20000001036split D on bit 3 from the right
110000101136placed
90000100136placed
280001110036placed
160001000037split A on bit 3 from the right

First bits or last bits

The directory can be indexed by the last (low-order) bits of the hash or the first (high-order) bits, and textbooks differ. Ramakrishnan and Gehrke's Database Management Systems uses the last bits; Wikipedia's worked example and many lecture notes use the first bits. With the last bits, doubling the directory is a copy of the whole directory placed after itself; with the first bits, each entry is duplicated in place. The two give different buckets for the same keys, so check which one your course uses. The same twelve keys, buckets of two, 8-bit hash:

ConventionGlobal depthBucketsFinal buckets (local depth)
Last bits37A(3): 16 B(3): 25 9 D(3): 18 2 C(2): 7 11 G(3): 4 28 E(3): 13 21 F(3): 30
First bits611A(6): 2 H(6): 4 7 F(6): 11 9 I(6): 13 E(6): 18 16 K(6): 21 G(6): 25 J(6): 30 28 D(3): C(2): B(1):

The keys here are small numbers, so with the first bits of an 8-bit hash they all start with zeros and the directory needs several doublings before the first bits tell them apart. Real hash functions spread keys over all bits, which makes either convention work equally well; small exercise keys exaggerate the difference.

Deletion and merging

Deleting a key removes it from its bucket. Merging is optional, and textbooks again differ. A bucket can merge with its split image, the bucket it was split from or that was split from it, when both have the same local depth: either only when one of them becomes empty, or whenever their keys fit in one bucket. The merged bucket's local depth drops by one, and when no bucket has a local depth equal to the global depth, the directory halves.

Many systems skip merging altogether, since a table that shrank once will often grow again and merging costs writes; the "Keep buckets" setting does that.

How full the buckets get

A bucket that splits leaves two buckets about half full, so for random keys the average fill settles near ln 2, about 69%. The directory grows faster than the buckets, because a doubling is triggered by the single deepest bucket. Inserting 20,000 random 30-bit keys, averaged over eight runs:

Bucket sizeAverage fillDirectory entries per bucket
269.3%308.51
469.2%17.01
869.2%5.11
1668.1%2.23
3265.7%2.15

Skewed keys are worse. The keys 0, 64, 128, 192, 32, 96 all end in five zero bits, so with the last bits and buckets of two the directory grows to 128 entries (global depth 7) for only 8 buckets. A good hash function avoids this; small exercise keys often do not.

Where it is used

Extendible hashing is a standard topic in database courses next to B+ trees, as the other main way to build an index on disk. A hash index answers equality lookups in about two page reads but cannot answer range queries, which is why databases default to B+ trees. File systems use it for large directories: Wikipedia lists ZFS, GPFS, the Global File System and SpadFS among file systems that do.

History

Ronald Fagin, Jürg Nievergelt, Nicholas Pippenger and H. Raymond Strong described extendible hashing in "Extendible Hashing: A Fast Access Method for Dynamic Files" in ACM Transactions on Database Systems in 1979, presenting it as an alternative to balanced trees that guarantees at most two page faults per lookup. Witold Litwin's linear hashing followed in 1980, removing the directory at the cost of overflow pages.

Extendible hashing questions and answers

What is the difference between global depth and local depth?

The global depth d is the number of hash bits the directory uses, so the directory has 2^d entries. Each bucket has its own local depth l ≤ d: the number of bits all of its keys are known to share. A bucket with local depth l is pointed to by 2^(d − l) directory entries.

When does the directory double in extendible hashing?

Only when a full bucket must split and its local depth already equals the global depth. Then no spare directory entry points to it, so the directory doubles (each new entry copies its partner’s pointer) and the bucket splits. If the bucket’s local depth is smaller, it splits without touching the directory size.

Does extendible hashing use the first or the last bits of the hash?

Either works, and textbooks differ. Ramakrishnan and Gehrke’s Database Management Systems uses the last (low-order) bits, which lets the directory double by copying it as one block. Many course notes and Wikipedia’s example use the first (high-order) bits of a fixed-width hash. The same keys give different buckets, so this page lets you switch.

What happens when all keys in a bucket have the same hash bits?

Splitting cannot separate keys whose hashes agree on every bit, so the bucket would split forever. Real systems add an overflow page for such a bucket; this simulator reports the key that could not be placed.

How full are extendible hashing buckets?

On average about 69%, which is ln 2, for random keys. Inserting 20,000 random keys into buckets of 4 in this model filled them to 69.2%. The directory is the cost: it had about 17.0 entries per bucket.

What is the difference between extendible hashing and linear hashing?

Extendible hashing keeps a directory and splits exactly the bucket that overflows, so lookups take one directory access and one bucket access. Linear hashing (Litwin, 1980) has no directory: it splits buckets in a fixed round-robin order whether or not they overflowed, and handles the overflow meanwhile with overflow pages.

Further reading

Published