Separate the storeage requirement from the datastructure.
You say you want contiguous memory - I assume then that you want to grab a chunk of memory and work entirely within that memory rather than allocating more fragments over time.
Now simplest case withing that is a queue implemented over ring-buffer within your memory chunk. I assume that you want something better, as you don't have fifo happening here.
So some form of balanced tree sounds like what you need. The choice probably depends on what patterns there are withing the arriving keys. Random? Ascending?
A wrinkle is to allocate memory from your chunk rather than using the normal heap allocator and that probably implies keeping a free list too.
It would be interesting to know why you value a contiguous block of memory.