Priority Queue using MultiMap - Java - java

I have to implement Priority Queue using MultiMap. I use MultiMap from Google Collections.
The following code creates a MultiMap and adds few elements into it.
Multimap<Integer, String> multimap = HashMultimap.create();
multimap.put(5,"example");
multimap.put(1,"is");
multimap.put(1,"this");
multimap.put(4,"some");
Now my problem is how to write the pop method?
I think that there should be a for loop and it should be iterating through MultiMap.
The lowest key should be the highest priority, so in C++ I would set a pointer to the first element and increment it. How to do it in Java?

The HashMultimap you're using won't give you any help in efficiently selecting the lowest element. Instead use a TreeMultimap (also in Google Collections) which lets you specify an ordering and iterate through the items in the list in that order. For instance:
for (Map.Entry<Integer, String> entry : multimap.entries()) {
System.out.println("Item " + entry.getValue() + " has priority " + entry.getKey();
}
You'll notice that this always prints out entries in priority order, so to get the first-priority element you can just do multimap.entries().iterator().next() (assuming you know the map has at least one element).
See the TreeMultimap documentation for more information.

If I'm understanding correctly that you're using Multimap as the internals for your own PriorityQueue class, rather than just trying to use Multimap as a priority queue, then you should probably keep a SortedSet (I'll call it sortedKeys) of all the keys. Then you can use
multimap.get(sortedKeys.first()) to pop the first element.
By "keeping a SortedSet", I mean that each time you add something to your Multimap, add its key to a SortedSet. When you remove items from your Multimap, remove their keys from the SortedSet. The goal being that your SortedSet stays equal to Multimap.keySet(), but without the overhead of calling SortedSet.clear(); SortedSet.addAll(...) all the time.
The alternative is going to be creating a SortedSet each time which would be much slower. It may help you understand what I'm saying though:
public Collection<V> pop() {
SortedSet keys = new TreeSet(multimap.keySet());
return multimap.get(keys.first());
}

Could you simply use the PriorityQueue class in the JDK?
With the TreeMultimap approach jacobm suggested, the following code is more concise.
Iterator<String> iterator = multimap.values().iterator();
String value = iterator.next();
iterator.remove();

Related

Navigable Map - Sorted Map yet un-ordered

Hi everyone please help, I discovered the NavigableMap today and initially it worked for me until I did the following.
When I populate the NavigableMap, notice from the end of the string value, I have added the values 1-4 and then 5.
The string layout is for example "23816012269<1>", the last value <#> makes this unique because I am using it later in the code.
All values up until 4 are duplicates (23816012269) , then 23806012269<5> is a new value prefixed with a different string/number and I will continue with new duplicates (suffixed with the next sequence <5> <#> number etc).
The problem is, when I populate the NavigableMap in the order that you see below, it puts ("238060122695",...) at the first entry of the NavigableMap, even though this was added to the NavigableMap very last.
Now when I use the NavigableMap.firstEntry().getKey() it reads "238060122695" as the first entry.
I need to read 238160122691 as the first entry because this was added to the map as the first entry.
Delving into the string value I know that 2380 comes before 2381, regardless, why does it treat it as the first entry when I added it last, is it because of the SortedMap interface that does this.? How do I avoid
This is code in the order being executed:
NavigableMap.put("238160122691", arrayListValue);
NavigableMap.put("238160122692", arrayListValue);
NavigableMap.put("238160122693", arrayListValue);
NavigableMap.put("238160122694", arrayListValue);
NavigableMap.put("238060122695", arrayListValue);
A NavigableMap is sorted:
A SortedMap extended with navigation methods returning the closest matches for given search targets. [...]
A NavigableMap may be accessed and traversed in either ascending or descending key order.
If you want entries to be in insertion order, use a LinkedHashMap:
Hash table and linked list implementation of the Map interface, with predictable iteration order. This implementation differs from HashMap in that it maintains a doubly-linked list running through all of its entries. This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order).
Delving into the string value I know that 2380 comes before 2381, regardless, why does it treat it as the first entry when I added it last, is it because of the SortedMap interface that does this?
There seems to be a misunderstanding of what NavigableMap and its implementing classing like TreeMap are doing. They do not sort the elements in order of insertion, but by their natural order (i.e. how they compareTo each other), or given another Comparator.
How do I avoid?
Well, you could wrap your string keys into a data structure that also has a number showing when it was inserted into the map, and provide a Comparator or compareTo method that sorts by that number. But more likely, NavigableMap is just not the right data structure for you. Have you considered just using a List or Queue, or maybe a LinkedHashMap as suggested in comments.
Thank you All, I have moved back to the LinkedList as suggested by everyone.
I then found the use of the ListIterator to find the the next entry and stored that in a variable to compare to the next Iteration.
ListIterator<Map.Entry<String, ArrayList<DataModel>>> listIterator = new LinkedList(myHashMap.entrySet()).listIterator();
String previousk, nextk = null;
Boolean entered = false;
while (listIterator.hasNext())
{
if(entered){
previousk = nextk.substring(0,12);
if(previousk != nextk.substring(0,12)){
*Set the flag here to be used*
}
}
nextk = listIterator.next().getKey();
entered = true;
System.out.println(nextk);
}

Why can't we just use its iterator or a for-each loop to visit the values in a java Map(HashMap or TreeMap) in order?

I am a beginner in Java. Please explain it as plain as possible.
I am putting a dummy code, because this site didn't let me post the question without this:
public void printSorted(PrintStream out) {
TreeMap<Integer,String> map2 = new TreeMap<Integer,String>();
for(Map.Entry<String,Integer> entry : concord.entrySet()){
map2.put(entry.getValue(), entry.getKey());
}//NavigableMap nmap=treemap.descendingMap();
for(Map.Entry<Integer,String> entry2 : map2.descendingMap().entrySet()){
System.out.println(entry2.getValue()+ " " + entry2.getKey());
}
}
Why can't we just use its iterator or a for-each loop to visit the values in a java Map(HashMap or TreeMap) in order?
Because those two classes do not maintain the values in any order. (Apart from the implied order of the keys ... in the TreeMap case.)
Indeed, there is not even a requirement on the value type of a Map that it be orderable.
If you want / need the values of a map in order:
If the ordering you want is "entry insertion order" or "entry least recently used", then use a LinkedHashMap.
For other orderings, you can copy the list of values (or the set of entries) into a separate set and then sort it. (Or you can do the equivalent with streams without an explicit copy.) But the point is that the Map itself won't / can't maintain the ordering you have just created by sorting.
If you want to avoid the cost of repeated sorting, use a separate (incrementally updatable) data structure to keep a sorted list or set of the values.
P.S. If you actually are asking about iterating the keys or entries in order, then TreeMap already does that. And ...
why do we use Map iterator and not use for/each loop?
We can do either. Both work. And indeed, a for each loop uses the Iterator under the covers.
You only need to use an iterator explicitly if you want to explicitly call methods on the iterator; e.g. Iterator::remove()

Data structure that has key-value mapping as well as ordering

I need a data structure that provides key-value mappings, like a Map, but that also allows me to fetch the key based on an (int) index (e.g. myKey = myDS.get(index)), without having to iterate over the data structure to get the key at the desired index.
I thought of using LinkedHashMap, but I don't see a way to get the key at a given index. Am I missing something in LinkedHashMap? Or is there another data structure I can use?
EDIT:
This is not a duplicate. The correct answer to the other question is to use some sort of SortedMap; however, that is not the correct answer to this question, since I'd like to be able to retrieve an Entry from the data structure via an Integer index, which is not supported in any Java library.
LinkedHashMap provides a hash table/doubly linked list implementation of the Map interface. Since it extends HashMap, it's still backed by an array, but there is also a doubly-linked list of Entry objects to ensure that the iteration order is predictable.
So, basically what it means is that when you iterate through the map like so:
for (Map.Entry<keyType,valueType>> entry : linkedHashMap.entrySet())
{
System.out.println("Key: " + entry.getKey().toString() +
" Value: " + entry.getValue.toString());
}
it will print in the order that you added the keys, as opposed to a non-linked Map, which will not print in insertion order. You cannot access the elements of the array like you want to, because the array that backs the hash is not in order. Only the doubly linked list is ordered.
Solution:
What you are looking for is a LinkedMap from Apache Commons.
AFAIK, there is no single data structure that will do this. There is certainly not one in the standard Java collection suite.
Also LinkedHashMap is not the solution because you cannot efficiently index a LinkedHashMap.
If you want to do index-based lookup as well as keep-based lookup, solution needs to be a combination of two data structures.
A Map<Key, Value> and an ArrayList<Value> is the simpler approach, but it has a couple of problems:
- Insertion and deletion of values from the ArrayList is expensive, unless you are inserting / deleting at the tail end of the list.
- Insertion and deletion makes the list positions unstable,.
If you want stable indexes and scalable insertion and deletion, then you need a Map<Key, Value> and a Map<Integer, Value> ... and a way to manage (i.e. recycle) the index values.
The Apache Commons LinkedMap class is a possible solution, except that it suffers from the problem that index values are not stable in the face of insertions and deletions.
How about using:
Map<String, String> map = new LinkedHashMap<String, String>();
List<Entry<String, String>> mapAsList = new ArrayList<Map.Entry<String,String>>(map.entrySet());
mapAsList.get(index);
I do not believe there is a collection for this; collections are either based on the idea that you want to know exactly where an element is (lists) or that you want quick access based on some key or criteria (maps); doing both would be very resource-intensive to maintain.
Of course, you can make something like this, as rocketboy's answer suggests, but I'm guessing it's not really possible to make efficient.
There is no direct DS in the standard Java Collections API to provide a indexed map. However, the following should let you achieve the result:
// An ordered map
Map<K, V> map = new LinkedHashMap<K, V>();
// To create indexed list, copy the references into an ArrayList (backed by an array)
List<Entry<K, V>> indexedList = new ArrayList<Map.Entry<K, V>>(map.entrySet());
// Get the i'th term
<Map.Entry<K,V>> entry = indexedList.get(index);
K key = entry.getKey();
V value = entry.getValue();
You might still want to retain the concerns of data persistence in the map separate from the retrieval.
Update:
Or use LinkedMap from Apache Commons as suggested by Steve.

How to avoid items being re-ordered when put into java HashMap

I'm creating a new Map and pushing strings into it (no big deal) -but I've noticed that the strings are being re-ordered as the map grows. Is it possible to stop this re-ordering that occurs so the items in the map retain the order the were put in with?
Map<String,String> x = new HashMap<String, String>();
x.put("a","b");
x.put("a","c");
x.put("a","d");
x.put("1","2");
x.put("1","3");
x.put("1","4");
//this shows them out of order sadly...
for (Map.Entry<String, String> entry : x.entrySet()) {
System.out.println("IN THIS ORDER ... " + entry.getValue());
}
If you care about order, you can use a SortedMap. The actual class which implements the interface (at least for most scenarios) is a TreeMap. Alternatively, LinkedHashMap also maintains its order, while still utilizing a hashtable-based container.
You can keep it with LinkedHashMap.
A HashMap in java is not sorted http://download.oracle.com/javase/1,5.0/docs/api/java/util/HashMap.html. If you want predictable iteration order use a LinkedHashMap instead: http://download.oracle.com/javase/1.4.2/docs/api/java/util/LinkedHashMap.html
Heres a good discussion on the difference: How is the implementation of LinkedHashMap different from HashMap?
The previous answers are correct in that you should use an implementation of Map that maintains ordering. LinkedHashMap and SortedMap each do these things.
However, the takeaway point is that not all collections maintain order and if order is important to you, you should choose the appropriate implementation. Generic HashMaps do not maintain order, do not claim to do so and cannot be set to do so.

Java Map question

I have one Map that contains some names and numbers
Map<String,Integer> abc = new HashMap<String,Integer>();
It works fine. I can put some values in it but when I call it in different class it gives me wrong order. For example:
I putted
abc.put("a",1);
abc.put("b",5);
abc.put("c",3);
Iterator<String> iter = abc.keySet().iterator();
while (iter.hasNext()) {
String name = iter.next();
System.out.println(name);
}
some time it returns the order (b,a,c) and some time (a,c,b).
What is wrong with it? Is there any step that I am missing when I call this map?
Edit:
I changed to HashMap and result is still same
The only thing that's wrong is your expectations. The Map interface makes no guarantees about iteration order, and the HashMap implementation is based on hash functions which means the iteration order is basically random, and will sometimes change completely when new elements are added.
If you want a specific iteration order, you have thee options:
The SortedMap interfaces with its TreeMap implementation - these guarantee an iteration order according to the natural ordering of the keys (or an ordering imposed by a Comparator instance)
The LinkedHashMap class iterates in the order the elements were added to the map.
Use a List instead of a Map - this has a well-defined iteration order that you can influence in detail.
I think you need LinkedHashMap.
A TreeMap will always have keys in their natural order (unless you provide a comparator) If you are seeing the order any differently it will be the way you are looking at the map and what you are doing with it. If in doubt, use a debugger and you will see the order is sorted.
If you wish to get map values in the same order you used to insert them use LinkedHashMap instead.

Categories

Resources