I need a data structure to do a get / find in Log N time and iterate starting from the object that was returned by the get operation. The iterator should iterate in the same order in which elements are inserted into the data structure.
Can I achieve this using TreeSet ? Or any other data structure?
Thanks!
This answer assumes that you want to get / find items by value, as opposed to access by insertion sequence number. I assume that this value is completely unrelated to the order in which items are inserted.
The closest you can get with standard Java foundation classes is a LinkedHashSet. This allows fast searching and iteration in insertion order. But it does not give you an iterator starting at a given position, so you'll have to implement that yourself. Either based on the LinkedHashSet, or using your own set implementation. I guess the easiest way would be using a HashSet and implementing the linking yourself. That way, you could use the set methods to look up the starting element, and use that to construct an iterator following the links. You could hide the links inside a wrapper object, so you won't have to expose them in your API.
If you start with a SortedMap<Integer, Object> and use keys for keeping track of the insertion order, you'll be able to use the fast tailMap operation for your needs.
If you need to find the position of an object by a key (or maybe by the object itself), then introduce another WeakHashMap<Object, Integer> that will map from your key to the position of the object. You'll then use the retrieved sequence number as the key into the former map.
Provided you are using Java 6, you can have a look at ConcurrentSkipListSet and ConcurrentSkipListMap.
Related
Is there a data structure that does the following:
Returns the value given the index
Returns the index given the value
Returns all values sorted by index as List<>
As far as I am aware, a HashMap supports property 2, doesn't support properties 1 and 3.
An ArrayList supports 1 and 3 but not 2.
Is there something that fits my needs?
(1) and (2) describe a bi-directional map; the Guava library provides several implementations of this data structure.
Unfortunately there isn't a SortedBiMap class (presently), however depending on your specific constraints you may be able to address (3) in different ways.
For example, the simplest thing to do would be to create a new wrapping type that contains a BiMap<Integer, V> and a List<V> and ensures the two data structures are kept in sync. This may be inefficient for some use-cases (e.g. removals are O(n) due to the backing list) but may well be all you need.
Alternatively you could try to loosen constraint (3) if you don't really need a List, but just need to be able to iterate in a fixed order, in which case you could probably use Guava's ImmutableBiMap, which is guaranteed to iterate in insertion-order.
Otherwise, you could probably create your own SortedBiMap type modeled after HashBiMap but using TreeMap instead of HashMap. This would allow you to iterate over the keys in order (e.g. 0->n) regardless of their insertion order.
List (Any List including ArrayList) supports all 3 of your requirments. 1 and 3 you already know about, for #2 see method indexOf(). Also see related method lastIndexOf()
Is there a Java data structure that satisfies the following requirements?
Indexed access. (i.e., i should be able to retrieve objects with get(i))
Constant time get() & contains() methods
Should enforce ordering (enforced by Comparator)
Should be mutable
I could not find any in Oracle's JDK or Guava that gives the above listed features out of the box
List provides indexed access & some kind of ordering but not constant-time contains(). SortedSet and SortedMap provide constant-time contains() and sorting but not indexed access!!
Am I missing something or is there any data structure out there that could be manipulated to provide the features listed above?
My current solution:
A combination of HashMap & ArrayList => I use ArrayList to store the sorted keys which provides indexed access and use HashMap for constant-time contains() method. I just wanna make sure that I am not trying to re-invent something that has already been done
Why I need this:
Let's call this data structure SortedDataStore
I am developing an Android app & most of the UI in that is a list of items and these items are pulled off the local db. (the local db gets its data from a remote server). The UI is populated using RecyclerView and I need constant-time indexed access to get the object from my SortedDataStore and populate the views. Since the order of items is decided based on their attributes, there is a need for sorting. Also the data gets updated a lot (items get modified, deleted and new items get added). When the new data comes in, I check against my SortedDataStore if it should be deleted, or added or modified (and moved to another index) for which I need constant-time contains() & mutability.
Based on what you've described as your expected data size, ArrayList seems like it would actually be just fine in practice -- your data isn't big enough for the linear-time factor to matter that much.
Otherwise, what you're doing is the right solution; there's no provided mutable data structure that does all that at once.
If you can avoid mutation, Guava's ImmutableSet satisfies the rest of your demands. You can use ImmutableSet.asList().get(index) to get out elements by index in O(1) time, and otherwise it supports O(1) contains and insertion order.
An ArrayList satisfies the three requirements:
Indexed access, using get(int i)
Constant time access, using get(int i)
Order by insertion, using add(Object o)
Java's LinkedHashMap satisfies your requirements if you use an index as your key.
Indexed access: use get(i)
Constant time get() & contains() methods: use get(i) and containsKey()
Should enforce ordering (enforced by Comparator): see note
Should be mutable: yes
Note
If you want a custom comparator, extend the Comparable interface and #Override the compareTo() method on the class of the child object.
comparator for LinkedHashMap
I need to store unique objects in some datastructure, but also I need access by index like in ArrayList or plain array. Maybe there is some elegant way to do this without using convertions from set to array, iteration through all elemnts, checking value while adding to ArrayList and others.
I would be grateful for any help and advices.
You should have a look at ListOrderedSet from Apache Commons Collections:
Decorates another Set to ensure that the order of addition is retained and used by the iterator.
If an object is added to the set for a second time, it will remain in the original position in the iteration. The order can be observed from the set via the iterator or toArray methods.
The ListOrderedSet also has various useful direct methods. These include many from List, such as get(int), remove(int) and indexOf(int). An unmodifiable List view of the set can be obtained via asList().
Make your own class containing a HashSet<T> and an ArrayList<T>. For the add/append operation, if the element is not already in the set, append it to the list and add it to the HashSet. You'll use about twice as much memory as a normal ArrayList, but you'll get O(1) random access and contains operations.
I have a multiset in guava and I would like to retrieve the number of instances of a given element without iterating over this multiset (I don't want to iterate because I assume that iterating takes quite some time, as it looks through all the collection).
To do that, I was thinking first to use the entryset() method of multiset, to obtain a set with single instances and their corresponding count. Then, transform this set into a hashmap (where keys are the elements of my set, and values are their instance count). Because then I can use the methods of hashmap to directly retrieve a value from its key - done! But this makes sense only if I can transform the set into the hashmap in a quick way (without iterating trhough all elements): is it possible?
(as I said I expect this question to be flawed on multiple counts, I'd be happy if you could shed light on the conceptual mistakes I probably make here. Thx!)
Simply invoke count(element) on your multiset -- voila!
You may know in Guava Multiset is an interface, not a class.
If you just want to know the repeated number of an element, call Multiset.count(Object element).
Please forget my following statement:
Then if you are using a popular implementation HashMultiset, there is already a HashMap<E, AtomicInteger> working under the scene.
That is, when the HashMultiset iterates, also a HashMap iterates. No need to transform into another HashMap.
i use a hashmap to store some data, but i need to keep it in ascending order whenever new data saved to the hashmap or old data move out of the hashmap. but hashmap itself doesn't suppport order, what data structure i can use to support order? Thanks
TreeMap would be the canonical sorted map implementation. Note that this is sorted on the keys, which I presume is what you're after, but if not it won't be suitable.
Since Java 6 also comes with a SortedMap interface, you can look at the list of classes which implement it (on the linked Javadoc page), and choose between those. Implementing this method only guarantees that they have some sort of defined iteration order, you'd have to read the descriptions of each class to see if it's what you like.
TreeMap isn't a hashmap, in that it isn't backed by a hashtable to provide amortised O(1) inserts. However, it's not possible to maintain a sorted map with O(1) inserts anyway (since you have to inspect at least some of the existing elements to work out where the new element should go), and hence the O(lg n) performance of TreeMap is as good as you'll get in this case.
LinkedHashMap may be what you're looking for.
http://download.oracle.com/javase/1.4.2/docs/api/java/util/LinkedHashMap.html