I require a map that supports 3 operations: "insert", "remove" and "iterate in sorted order". This is exactly the interface of TreeMap
in Java. That being said it can also be implemented by using a HashMap
and sorting it every time before iteration. To analyze the different approaches, lets say I perform n
inserts and m
removes, 'r' reads and then iterate.
With TreeMap
we have the following implementation:
TreeMap<Integer, Integer> tm = Maps.newTreeMap();
for (int i=0;i<n;++i) {tm.put(i, 2*i);} // O(n*log(n))
for (int i=0;i<m;++i) {tm.remove(i);} // O(m*log(m))
for (int i=0;i<r;++i) {tm.get(i);} // O(r*log(n-m))
for (Integer i : tm) {print(i);} // O(n-m)
All told we have a total run time of O(n*log(n) + m*log(m) + r*log(n-m))
With HashMap
we have the following implementation:
HashMap<Integer, Integer> hm = Maps.newHashMap();
for (int i=0;i<n;++i) {hm.put(i, 2*i);} // O(n)
for (int i=0;i<m;++i) {hm.remove(i);} // O(m)
for (int i=0;i<r;++i) {hm.get(i);} // O(r)
List<Integer> sortedList = Lists.newArrayList(hm.keySet()); // O(n-m)
Collections.sort(sortedList); // O((n-m)*log(n-m))
for (Integer i : sortedList) {print(i);} // O(n-m)
All told we have a total run time of O((n-m)*log(n-m))
.
For all n,m O(n*log(n) + m*log(m) + r*log(n-m)) > O((n-m)*log(n-m))
.
My question therefore is, what is the use case where a TreeMap
is better than a HashMap
? Is it only better if you need to iterate over the map many (let's say k
) times (in which case, if k
is >> log(n)
the run time for TreeMap
will be O(k*(n-m))
whereas for HashMap
will be O(k*(n-m)*log(n-m)))
? Regardless, if you are only performing O(log(n))
iterations (this does sound like such a sane use case), HashMap
will outperform TreeMap
. Am I missing something?