问题
I am trying to find key
with minimum value in Map
shown below.
Map<Node, Integer> freeMap = new TreeMap<>();
Node minNode = null;
for (Map.Entry<Node, Integer> entry : freeMap.entrySet()) {
if (minNode == null) {
minNode = entry.getKey();
} else {
if (entry.getValue() < freeMap.get(minNode)) {
minNode = entry.getKey();
}
}
}
Firstly, Is there a straight forward way to find key
with minimum value
than using foreach
loop. Secondly, can you suggest some alternate data structure approach which can be used to store a Node
object and an associated Integer
value, so I can fetch entry
with minimum value in constant time O(1).
回答1:
If your goal is to improve time complexity, there's really only one possible change, from O(n log n) to O(n):
Map<Node, Integer> freeMap = new TreeMap<>();
Map.Entry<Node, Integer> minEntry = null;
for (Map.Entry<Node, Integer> entry : freeMap.entrySet()) {
if (minEntry == null || entry.getValue() < minEntry.getValue()) {
minEntry = entry;
}
}
Node minNode = minEntry.getKey();
回答2:
I suspect that Integer
values are not unique in your system.
If this is the case, I suggest you use TreeMultimap from guava library, and use Integer
value as a key.
TreeMultimap<Integer, Node> freeMap = new TreeMultimap<>();
Node minNode =
freeMap.isEmpty()
? null
: freeMap.entries().iterator().next().getValue();
回答3:
Minor improvement not a whole bunch :
Map<Node, Integer> freeMap = new TreeMap<Node, Integer>();
Node minNode = freeMap.isEmpty() ? null : (Node) freeMap.entrySet().iterator().next();
for (Map.Entry<Node, Integer> entry : freeMap.entrySet()) {
if (entry.getValue() < freeMap.get(minNode)) {
minNode = entry.getKey();
}
}
Got the if check out of the loop.
回答4:
Data Structure for O(1) Min For an alternative data structure, how about a Priority Queue.
You can either use a custom Comparator or have your data type implement Comparable.
From the javadoc:
Implementation note: this implementation provides O(log(n)) time for the enqueing and dequeing methods (offer, poll, remove() and add); linear time for the remove(Object) and contains(Object) methods; and constant time for the retrieval methods (peek, element, and size).
Data Structure for O(1) Min and amortized O(1) find
If you want both efficient min and efficient find and you control access to the data structure (otherwise what is the point of the question?) you can just roll out your own by extending Java's HashMap to keep track of the minimum element.
You will have to override the put
, putAll
and remove
methods. In each case, you can just call the super class method (e.g. super.put(key, value)
) and then update the minimum element, which is kept as an instance member of your newly defined class.
Note that this increases the remove time to (O(N)) (since you will have to update the minimum value).
回答5:
You can define your own Comparator and use Collections.min. Example:
Comparator<Entry<Node, Integer>> customComparator = new Comparator<>() {
@Override
public int compare(Entry<Node, Integer> o1, Entry<Node, Integer> o2){
return (int)(o1.getValue() - o2.getValue());
}
@Override
public boolean equals(Object obj) {
return false;
}
};
Entry<Node, Integer> minVal = Collections.min(freeMap.entrySet(), customComparator);
Hope this helps :)
回答6:
The keys for a concise, efficient and elegant solution here are the Collections#min method and the Map.Entry#comparingByValue method
The first method can be applied to the entrySet
of the map, and the second one provides a Comparator
that compares map Entry
objects by their value. So the solution is a one-liner, and you can either obtain the entry or the key directly, as shown in this example:
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
public class KeyWithMinValue
{
public static void main(String[] args)
{
Map<String, Integer> map = new LinkedHashMap<String, Integer>();
map.put("Zero", 0);
map.put("One", 1);
map.put("Two", 2);
map.put("Three", 3);
map.put("Four", 4);
// Obtain the entry with the minimum value:
Entry<String, Integer> entryWithMinValue = Collections.min(
map.entrySet(), Entry.comparingByValue());
System.out.println(entryWithMinValue);
// Or directly obtain the key, if you only need that:
String keyWithMinValue = Collections.min(
map.entrySet(), Entry.comparingByValue()).getKey();
System.out.println(keyWithMinValue);
}
}
来源:https://stackoverflow.com/questions/26513747/efficient-way-to-find-min-value-in-map