Most efficient way to keep a collection in Java? - java

Currently, I have a LinkedList which stores a custom Node class. The Nodes are currently removed in order and evaluated, which generally adds more Nodes back into the LinkedList, treating it like a Queue.
But in reality I don't care about maintaining the order of the Nodes because the order they are being added or removed doesn't matter. You can remove the 1st, 54th, or 1032nd Node from the List, it doesn't matter. All that matters is the Nodes are being processed quickly, which means one is removed (at random), mutated, then added back along with several variations of it (once again the order doesn't matter).
Since I haven't been able to find a Java Bag implementation, what is the most efficient way to maintain this type of collection ?
PS Out of laziness I have avoid using arrays because the collection of nodes could theoretically range from 1 Node to 3^64 Nodes in size, though it's more likely to stay under a million.

The Java HashSet or TreeSet types might be good here, since they represent unordered collections of elements that support quick insertion and deletion of elements. That said, you can't possibly hold 364 values in memory, since that's appromately 3.4336838 × 1030, a number vastly bigger than any amount of RAM that I know of can hold.
EDIT: Based on the described use case (support efficient insertion and removal of random elements), you might want to adopt the approach described in this older question for building a data structure that does just that. Intuitively, you would use an ArrayList, then remove elements by swapping them to the end of the ArrayList and removing them. This gives O(1) insertion and O(1) removal with extremely low overhead.
Hope this helps!

Related

Java List/Set performance

I must work with a Collection, and I am not sure about using a List or a Set. This collection must be sorted, but not by the order of insertion but for another one, so each time a new item is added, a Comparator should be executed in order to reorder the Collection. So, for this reason, an ArrayList could be the best option.
Removing objects from that Collection must be possible too, furthermore, I would really appreciate using removeIf method, so a Set would be the best option here.
Getting and iterating over the Collection will be the most repeated scenario, so it must have a good performance in this scenario.
Seeing that, I think that a Set would be a good decision, however, I was thinking about converting the Set into a List when adding items, then, once the list has been resorted, converting it back to a Set. Is it bad performing? What do you think?
Thanks in advance
Unless you have bulk inserts during which you would need no sorting, TreeSet is fine. Simply measure both solutions.
With TreeSet inserting already ordered items, like rereading a set from disk, performs bad in that even a balanced tree, will have a bit too large depth. That however can be remedied.
For better performance you might go for a B-tree (needs 3rd party code) instead of the binary TreeSet. Measure that too, as typically a facet such as deletion with rebalancing might be done suboptimally.
This depends a lot on how you fill and use your collection and performance of which operation is the most important.
Do you fill the collection with items at once? Or add new elements from time to time? Does the performance of adding elements matter? Or only the iteration performance is important?
If performance is critical, it might make sense to implement a few solutions and compare their performance using a benchmark.
I personally don't believe that iteration performance of a TreeSet is that much worse that ArrayLists or LinkedLists or LinkedHashMaps. Especially compared to linked data structures. Iteration on a tree should not be that different in the performance. But I have no data, so this is just a belief here.
Below are two implementation ideas.
First, if you load a lot of data at once and then add new items rather seldom, load the data into an ArrayList and sort it using Collections.sort. If you need to add another item do a binary search (Collections.binarySearch) and insert the element at the corresponding position. Wrap it all in a custom List implementation and you're good to go.
Next, if you fill the collection with the data "in the beginning" and then the collection is hardly modified, you may simply cache the iteration order in an ArrayList. Every time the collection is modified, reset this list and. When iteration is requested and the list is not null, just use it, otherwise first fill it in the order of the sorted set.

Why is add at specific index slower in LinkedLists than in ArrayLists

I was checking this chart containing performances comparisons among lists:
And I find it very odd that adding and removing elements at a specific index performs faster in an ArrayList than it does in a LinkedList. Is this chart wrong? The whole idea of a LinkedList is to improve such operations, while paying with reduced iteration performance. But this chart seems to indicate that Java's implementation of LinkedLists is very poorly done.
Should I trust the chart? And if so, why Java LinkedLists perform so bad?
The whole idea of a LinkedList is to improve such operations, while paying with reduced iteration performance.
No, the idea of a linked list is to make adding or removing at the end or beginning very cheap... or if you have a reference to a node object already, adding around that or removing it is very cheap too. (I don't think the Java API exposes the nodes, but some other platforms like .NET do.)
To add at an index within a linked list, the implementation first has to navigate to the node at that index... which is an O(n) operation. Once it's got there, the add is cheap. So adding by index near the start (or end with a smart implementation) is cheap, but adding by index near the middle is expensive.
With an ArrayList, the expense comes from:
Copying the existing elements beyond the index you're adding
Copying the whole thing is the buffer isn't big enough
A general information:
Making micro benchmark is influenced by many factors, so it is not so easy to define a micro benchmark that is reliable for little numbers.
The insertion can be seen as a two step process:
Find position
Insert element
The first step, find position, is done in O(n), the second step in O(1) for a LinkedList.
Using an ArrayList finding the position is O(1), instead the insertion is done in O(n). Moving records one position (to create space for a new element) is done using native libraries so it is a quite fast operation.

Speeding up a linked list?

I'm a student and fairly new to Java. I was looking over the different speeds achieved by the two collections in Java, Linked List, and ArrayList. I know that an ArrayList is much much faster at looking up and placing in values into its indexes. My question is:
how can one make a linked list faster, if at all possible?
Thanks for any help.
zmahir
When talking about speed, perhaps you mean complexity. Insertion and retrieval operations for ArrayList (and arrays) are O(1), while for LinkedList they are O(n). And this cannot be changed - it is 'by definition'.
O(n) means that in order to insert an object at a given position, or retrieve it, you must traverse, in the worst case, all (n) the items in the list. Hence n operations. For ArrayList this is only one operation.
You probably can't. You don't know the size (well, ok you can), nor the location of each element. To find element 100 in a linked list, you need to start with item 1, find it's link to item 2, etc. until you find 100. This makes inserting into this list a tedious job.
There are many alternatives depending on your exact goals. You can use b-trees or similar methods to split the large linked list into smaller ones. Or use hashlists if you want to quickly find items. Or use simple arrays. But if you want a list that performs like an ArrayList, why not use an ArrayList?
You can split off regions which are linked to the main linked list, so this gives you entry points directly inside the list so you don't have to walk up to them. See the subList method here: http://download.oracle.com/javase/1.4.2/docs/api/java/util/AbstractList.html. This is useful if you have a number of 'sentences' made out of words, say. You can use a separate linked list to iterate over the sentences, which are sublists of the main linked list.
You can also use a ListIterator when adding, removing, or accessing elements. This helps greatly with increasing the speed of sequential access. See the listIterator method for this, and the class: http://download.oracle.com/javase/1.4.2/docs/api/java/util/ListIterator.html.
Speed of a linked list could be improved by using skip lists: http://igoro.com/archive/skip-lists-are-fascinating/
a linked list uses pointers to walk through the items, so for example if you asked for the 5th item, the runtime will start from the first item and walks through each pointer until it reaches the 5th item.
there is really not much you can do about it. a linked list may not be a good choice if you need fast acces to items. although there are some optimizations for it such as creating a circular linked list or a double linked list where you can walk back and forth the list but this really depends on the business logic and the application requirements.
my advise is to avoid linked lists if it does not match your needs and changing to a different data structure might be the best approach.
As a general rule, data structures are designed to do certain things well. LinkedLists are designed to be faster than ArrayLists at inserting elements and removing elements and about the same as ArrayLists at iterating across the list in order. When you change the way a LinkedList works, you make it no longer a true LinkedList, so there's not really any way to modify them to be faster at something and still be a LinkedList.
You'll need to examine the way you're using this particular collection and decide whether a LinkedList is really the best data structure for your purposes. If you share with us how you're using it, and why you need it to be faster, then we can advise you on which data structure you ought to consider using.
Lots of people smarter than you or I have looked at the implementation of the Java collection classes. If there were an optimization to be made, they would have found it and already made it.
Since the collection classes are pretty much as optimized as they can be, our primary task should be to choose the correct one.
When choosing your collection type, don't forget about things like HashSet. If order doesn't matter, and you don't need to put duplicates in the collection, then HashSet may be appropriate.
I'm a student and fairly new to Java. ... how can one make a linked list faster, if at all possible?
The standard Java collection type (indeed all data structures implemented in any language!) represent compromises on various "measures" such as:
The amount of memory needed to represent the data structure.
The time taken to perform various operations; e.g. for a "list" the operations of interest are insertion, removal, indexing, contains, iteration and so on.
How easy or hard it is to integrate / reuse the collection type; see below.
So for instance:
ArrayList offers lower memory overheads, fast indexing (O(1)), but slow contains, random insertion and removal (O(N)).
LinkedList has higher memory overheads, slow indexing and contains (O(N)), but faster removal (O(1)) under certain circumstances.
The various performance measures are typically determines by the maths of the various data structures. For example, if you have a chain of nodes, the only way to get the ith node is to step through them from the beginning. This involves following i pointers.
Sometimes you can modify the data structures to improve one aspect of the performance. But this typically comes at the cost of some other aspect of the performance. (For example, you could add a separate index to make indexing of a linked list faster. But the cost of maintaining the index on insertion / deletion would mean that you'd probably be better of using an ArrayList.)
In some cases the integration / reuse requirements have significant impact on performance.
For example, it is theoretically possible to optimize a linked list's space usage by adding a next field to the list element type, combining the element and node objects and saving 16 or so bytes per list entry. However, this would make the list type less general (the member/element class would need to implement a specific interface), and has the restriction that an element can belong to at most one list at any time. These restrictions are so limiting that this approach is rarely used in Java.
For a second example, consider the problem of inserting at a given position in a linked list. For the LinkedList class, this is normally an O(N) operation, because you have to step through the list to find the position. In theory, if an application could find and remember a position, it should be able to perform the insertion at that position in O(1). Unfortunately, neither the List APIs provides no way to "remember" a position.
While neither of these examples is a fundamental roadblock to a developer "doing his own thing", they illustrate that using general data structure APIs and general implementations of those APIs has performance implications, and therefore represents a trade-off between performance and ease-of-use.
I'm a bit surprised by the answers here. There are big difference between the theoretical performance of LinkedLists and ArrayLists compared to the actual performance of the Java implementations.
What makes the Java LinkedList slower than a theoretical LinkedList is that it does a lot more than just the operations. For example it checks for concurrent modifications and other safeties.
If you know your use case, you can write a your own simple implementation of a LinkedList and it will be much faster.

Which Data Structure? LinkedList or Any Other in Java?

I have specific requirements for the data structure to be used in my program in Java. It (Data Structure) should be able to hold large amounts of data (not fixed), my main operations would be to add at the end, and delete/read from the beginning (LinkedLists look good soo far). But occasionally, I need to delete from the middle also and this is where LinkedLists are soo painful. Can anyone suggest me a way around this? Or any optimizations through which I can make deletion less painful in LinkedLists?
Thanks for the help!
A LinkedHashMap may suit your purpose
You'd use an iterator to pull stuff from the front
and lookup the entry by key when you needed to access the middle of the list
LinkedList falls down on random accesses. Deletion, without the random access look up, is constant time and so really not too bad for long lists.
ArrayList is generally fast. Inserts and removes from the middle are faster than you might expect because block memory moves are surprisingly fast. Removals and insertions near the start to cause all the following data to be moved down or up.
ArrayDeque is like ArrayList only it uses a circular buffer and has a strange interface.
Usual advice: try it.
you can try using linked list with a pointers after evey 10000th element so that you can reduce the time to find the middle which you wish to delete.
here are some different variations of linked list:
http://experimentgarden.blogspot.com/2009/08/performance-analysis-of-thirty-eight.html
LinkedHashMap is probably the way to go. Great for iteration, deque operations, and seeking into the middle. Costs extra in memory, though, as you'll need to manage a set of keys on top of your basic collection. Plus I think it'll leave 'gaps' in the spaces you've deleted, leading to a non-consecutive set of keys (shouldn't affect iteration, though).
Edit: Aha! I know what you need: A LinkedMultiSet! All the benefit of a LinkedHashMap, but without the superfluous key set. It's only a little more complex to use, though.
First you need to consider whether you will delete from the center of the list often compared to the length of the list. If your list has N items but you delete much less often than 1/N, don't worry about it. Use LinkedList or ArrayDeque as you prefer. (If your lists are occasionally huge and then shrink, but are mostly small, LinkedList is better as it's easy to recover the memory; otherwise, ArrayDeque doesn't need extra objects, so it's a bit faster and more compact--except the underlying array never shrinks.)
If, on the other hand, you delete quite a bit more often than 1/N, then you should consider a LinkedHashSet, which maintains a linked list queue on top of a hash set--but it is a set, so keep in mind that you can't store duplicate elements. This has the overhead of LinkedList and ArrayDeque put together, but if you're doing central deletes often, it'll likely be worth it.
The optimal structure, however--if you really need every last ounce of speed and are willing to spend the coding time to get it--would be a "resizable" array (i.e. reallocated when it was too small) with a circular buffer where you could blank out elements from the middle by setting them to null. (You could also reallocate the buffer when too much was empty if you had a perverse use case then.) I don't advise coding this unless you either really enjoy coding high-performance data structures or have good evidence that this is one of the key bottlenecks in your code and thus you really need it.

Data structures: Which should I use for these conditions?

This shouldn't be a difficult question, but I'd just like someone to bounce it off of before I continue. I simply need to decide what data structure to use based on these expected activities:
Will need to frequently iterate through in sorted order (starting at the head).
Will need to remove/restore arbitrary elements from the/a sorted view.
Later I'll be frequently resorting the data and working with multiple sorted views.
Also later I'll be frequently changing the position of elements within their sorted views.
This is in Java, by the way.
My best guess is that I'll either be rolling some custom Linked Hash Set (to arrange the links in sorted order) or possibly just using a Tree Set. But I'm still not completely sure yet. Recommendations?
Edit: I guess because of the arbitrary remove/restore, I should probably stick with a Tree Set, right?
Actually, not necessarily. Hmmm...
In theory, I'd say the right data structure is a multiway tree - preferably something like a B+ tree. Traditionally this is a disk-based data structure, but modern main memory has a lot of similar characteristics due to layers of cache and virtual memory.
In-order iteration of a B+ tree is very efficient because (1) you only iterate through the linked-list of leaf nodes - branch nodes aren't needed, and (2) you get extremely good locality.
Finding, removing and inserting arbitrary elements is log(n) as with any balanced tree, though with different constant factors.
Resorting within the tree is mostly a matter of choosing an algorithm that gives good performance when operating on a linked list of blocks (the leaf nodes), minimising the need to use leaf nodes - variants of quicksort or mergesort seem like likely candidates. Once the items are sorted in the branch nodes, just propogate the summary information back through the leaf nodes.
BUT - pragmatically, this is only something you'd do if you're very sure that you need it. Odds are good that you're better off using some standard container. Algorithm/data structure optimisation is the best kind of optimisation, but it can still be premature.
Standard LinkedHashSet or LinkedMultiset from google collections if you want your data structure to store not unique values.

Categories

Resources