For in easy but maybe not-so-efficient algorithm I'd do it like this:
1. expand the map to a list.
practically spoken: iterate through the map and add the key 'value-times' to the new list. Finally sort the list.
//...
List<Integer> field = new ArrayList<Integer>();
for (Integer key:map) {
for (int i = 0; i < map.get(key); i++) {
field.add(key);
}
}
Collections.sort(field);
2. calculate the median
now you have to implement a method int calculateMedian(List<Integer> sorted)
. This depends on the kind of median you need. If it's just the sample median, then the result is either the middlemost value (for lists with an odd number of elements) or the average of the two middlemost values (for lists with an even length). Note, that the list needs to be sorted!
(Ref: Sample Median / wikipedia)
OK, OK, even though Chris didn't mention efficiency, here's an idea how to calculate the sample median (!) without expanding the map...
Set<Integer> sortedKeys = new TreeSet<Integer>(map.keySet()); // just to be sure ;)
Integer median = null; // Using Integer to have a 'invalid/not found/etc' state
int total = 0;
for (Integer key:sortedKeys) {
total += map.get(key);
}
if (isOddNumber(total)) { // I don't have to implement everything, do I?
int counter = total / 2; // index starting with 0
for (Integer key:sortedKeys) {
middleMost -= map.get(key);
if (counter < 0) {
// the sample median was in the previous bin
break;
}
median = key;
}
} else {
int lower = total/2;
int upper = lower + 1;
for (Integer key:sortedKeys) {
lower -= map.get(key);
upper -= map.get(key);
if (lower < 0 && upper < 0) {
// both middlemost values are in the same bin
break;
} else (lower < 0 || upper < 0) {
// lower is in the previous, upper in the actual bin
median = (median + key) / 2; // now we need the average
break;
}
median = key;
}
}
(I have no compiler at hand - if it has to many syntax errors, treat it as pseudo code, please ;) )