BTW The next array needs to be an array of indexes, rather than pointers, so you can continue to follow the next chain.

A third alternative would be to use a chained hash table - which would be very similar to the collalesed table above.  The difference would be

i) the main hash table held indexes into your row array, rather than pointers.
ii) Your next array was based on indexes within your row array rather than the hash table.

The disadvantage is an extra indirection every time you look up an entry in the hash table.  You may find it is inisignificant though.

You could also get away with using 32bit values for the indexes and the next table for most of the time, which would mean there was no extra memory overhead over the current scheme (and would reduce the memory consumption for the non-many case).

(Thinking outloud...  could you use a class to encapsulate the hash table so that it switched from using 16/32/64 bit integers - since you already have to update all the indexes when the table expands.)  

However with the chained hashing you could possibly get by with a smaller hash table.

Resize the hash table becomes an interesting problem since you also need to walk the chains - although I don't think it is that tricky.

... requires quite a bit more discussion I think ...