I have this code below where I am inserting a new integer into a sorted LinkedList of ints but I do not think it is the "correct" way of doing things as I know there are singly linkedlist with pointer to the next value and doubly linkedlist with pointers to the next and previous value. I tried to use Nodes to implement the below case but Java is importing this import org.w3c.dom.Node (document object model) so got stuck.
Insertion Cases
Insert into Empty Array
If value to be inserted less than everything, insert in the beginning.
If value to be inserted greater than everything, insert in the last.
Could be in between if value less than/greater than certain values in LL.
import java.util.*;
public class MainLinkedList {
public static void main(String[] args) {
LinkedList<Integer> llist = new LinkedList<Integer>();
llist.add(10);
llist.add(30);
llist.add(50);
llist.add(60);
llist.add(90);
llist.add(1000);
System.out.println("Old LinkedList " + llist);
//WHat if you want to insert 70 in a sorted LinkedList
LinkedList<Integer> newllist = insertSortedLL(llist, 70);
System.out.println("New LinkedList " + newllist);
}
public static LinkedList<Integer> insertSortedLL(LinkedList<Integer> llist, int value){
llist.add(value);
Collections.sort(llist);
return llist;
}
}
If we use listIterator the complexity for doing get will be O(1).
public class OrderedList<T extends Comparable<T>> extends LinkedList<T> {
private static final long serialVersionUID = 1L;
public boolean orderedAdd(T element) {
ListIterator<T> itr = listIterator();
while(true) {
if (itr.hasNext() == false) {
itr.add(element);
return(true);
}
T elementInList = itr.next();
if (elementInList.compareTo(element) > 0) {
itr.previous();
itr.add(element);
System.out.println("Adding");
return(true);
}
}
}
}
This might serve your purpose perfectly:
Use this code:
import java.util.*;
public class MainLinkedList {
private static LinkedList<Integer> llist;
public static void main(String[] args) {
llist = new LinkedList<Integer>();
addValue(60);
addValue(30);
addValue(10);
addValue(-5);
addValue(1000);
addValue(50);
addValue(60);
addValue(90);
addValue(1000);
addValue(0);
addValue(100);
addValue(-1000);
System.out.println("Linked List is: " + llist);
}
private static void addValue(int val) {
if (llist.size() == 0) {
llist.add(val);
} else if (llist.get(0) > val) {
llist.add(0, val);
} else if (llist.get(llist.size() - 1) < val) {
llist.add(llist.size(), val);
} else {
int i = 0;
while (llist.get(i) < val) {
i++;
}
llist.add(i, val);
}
}
}
This one method will manage insertion in the List in sorted manner without using Collections.sort(list)
You can do it in log (N) time Complexity simply. No need to iterate through all the values. you can use binary search to add value to sorted linked list.just add the value at the position of upper bound of that function.
Check code... you may understand better.
public static int ubound(LinkedList<Integer> ln, int x) {
int l = 0;
int h = ln.size();
while (l < h) {
int mid = (l + h) / 2;
if (ln.get(mid) <= x) l = mid + 1;
else h = mid;
}
return l;
}
public void solve()
{
LinkedList<Integer> ln = new LinkedList<>();
ln.add(4);
ln.add(6);
ln.add(ubound(ln, 5), 5);
out.println(ln);
}
Output : [4, 5, 6]
you can learn about binary search more at : https://www.topcoder.com/community/data-science/data-science-tutorials/binary-search/
#Atrakeur
"sorting all the list each time you add a new element isn't efficient"
That's true, but if you need the list to always be in a sorted state, it is really the only option.
"The best way is to insert the element directly where it has to be (at his correct position). For this, you can loop all the positions to find where this number belong to"
This is exactly what the example code does.
"or use Collections.binarySearch to let this highly optimised search algorithm do this job for you"
Binary search is efficient, but only for random-access lists. So you could use an array list instead of a linked list, but then you have to deal with memory copies as the list grows. You're also going to consume more memory than you need if the capacity of the list is higher than the actual number of elements (which is pretty common).
So which data structure/approach to take is going to depend a lot on your storage and access requirements.
[edit]
Actually, there is one problem with the sample code: it results in multiple scans of the list when looping.
int i = 0;
while (llist.get(i) < val) {
i++;
}
llist.add(i, val);
The call to get(i) is going to traverse the list once to get to the ith position. Then the call to add(i, val) traverses it again. So this will be very slow.
A better approach would be to use a ListIterator to traverse the list and perform insertion. This interface defines an add() method that can be used to insert the element at the current position.
Have a look at com.google.common.collect.TreeMultiset.
This is effectively a sorted set that allows multiple instances of the same value.
It is a nice compromise for what you are trying to do. Insertion is cheaper than ArrayList, but you still get search benefits of binary/tree searches.
Linked list isn't the better implementation for a SortedList
Also, sorting all the list each time you add a new element isn't efficient.
The best way is to insert the element directly where it has to be (at his correct position).
For this, you can loop all the positions to find where this number belong to, then insert it, or use Collections.binarySearch to let this highly optimised search algorithm do this job for you.
BinarySearch return the index of the object if the object is found in the list (you can check for duplicates here if needed) or (-(insertion point) - 1) if the object isn't allready in the list (and insertion point is the index where the object need to be placed to maintains order)
You have to find where to insert the data by knowing the order criteria.
The simple method is to brute force search the insert position (go through the list, binary search...).
Another method, if you know the nature of your data, is to estimate an insertion position to cut down the number of checks. For example if you insert 'Zorro' and the list is alphabetically ordered you should start from the back of the list... or estimate where your letter may be (probably towards the end).
This can also work for numbers if you know where they come from and how they are distributed.
This is called interpolation search: http://en.wikipedia.org/wiki/Interpolation_search
Also think about batch insert:
If you insert a lot of data quickly you may consider doing many insertions in one go and only sort once afterwards.
Solution of Amruth, simplified:
public class OrderedList<T extends Comparable<T>> extends LinkedList<T> {
private static final long serialVersionUID = 1L;
public boolean orderedAdd(T element) {
ListIterator<T> itr = listIterator();
while(itr.hasNext()) {
if (itr.next().compareTo(element) > 0) {
itr.previous();
break;
}
}
itr.add(element);
}
}
Obviously it's O(n)
Related
More specifically: how to get the nth element of a LinkedHashSet (which has a predictable iteration order)? I want to retrieve the nth element inserted into this Set (which wasn't already present).
Is it better to use a List:
List<T> list = new ArrayList<T>(mySet);
T value = list.get(x); // x < mySet.size()
or the toArray(T [] a) method:
T [] array = mySet.toArray(new T[mySet.size()]);
T value = array[y]; // y < mySet.size()
Other than the (likely slight) performance differences, anything to watch out for? Any clear winner?
Edit 1
NB: It doesn't matter why I want the last-inserted element, all that matters is that I want it. LinkedHashSet was specifically chosen because it "defines the iteration ordering, which is the order in which elements were inserted into the set (insertion-order). Note that insertion order is not affected if an element is re-inserted into the set."
Edit 2
This question seems to have devolved into a discussion of whether any Set implementation can ever preserve original insertion order. So I put up some simple test code at http://pastebin.com/KZJ3ETx9 to show that yes, LinkedHashSet does indeed preserve insertion order (the same as its iteration order) as its Javadoc claims.
Edit 3
Modified the description of the problem so that everybody isn't too focused on retrieving the last element of the Set (I originally thought that the title of the question would be enough of a hint — obviously I was wrong).
This method is based on the updated requirement to return the nth element, rather than just the last element. If the source is e.g. a Set with identifier mySet, the last element can be selected by nthElement(mySet, mySet.size()-1).
If n is small compared to the size of the Set, this method may be faster than e.g. converting to an ArrayList.
/**
* Return an element selected by position in iteration order.
* #param data The source from which an element is to be selected
* #param n The index of the required element. If it is not in the
* range of elements of the iterable, the method returns null.
* #return The selected element.
*/
public static final <T> T nthElement(Iterable<T> data, int n){
int index = 0;
for(T element : data){
if(index == n){
return element;
}
index++;
}
return null;
}
I'd use the iterator of the LinkedHashSet if you want to retrieve the last element:
Iterator<T> it = linkedHashSet.iterator();
T value = null;
while (it.hasNext()) {
value = it.next();
}
After the loop execution value will be referring to the last element.
So I decided to go with a slight variation of the answer by #Juvanis.
To get at the nth element in a LinkedHashSet:
Iterator<T> itr = mySet.iterator();
int nth = y;
T value = null;
for(int i = 0; itr.hasNext(); i++) {
value = itr.next();
if (i == nth) {
break;
}
}
Version 2 of the code:
public class SetUtil {
#Nullable
public static <T> T nthElement(Set<T> set, int n) {
if (null != set && n >= 0 && n < set.size()) {
int count = 0;
for (T element : set) {
if (n == count)
return element;
count++;
}
}
return null;
}
}
NB: with some slight modifications the method above can be used for all Iterables<T>.
This avoids the overhead of ensuring that a Set and a List stay in sync, and also avoids having to create a new List every time (which will be more time-consuming than any amount of algorithmic complexity).
Obviously I am using a Set to ensure uniqueness and I'd rather avoid a lengthy explanation as to why I need indexed access.
You can go with below solution,
here i have added object of ModelClass in HashSet.
ModelClass m1 = null;
int nth=scanner.nextInt();
for(int index=0;index<hashset1.size();index++){
m1 = (ModelClass) itr.next();
if(nth == index) {
System.out.println(m1);
break;
}
}
Set is unordered so the information on the last element inserted is lost. You cannot as such get the last element inserted. So don't use Set in the first place, or, if you really want to keep track of the last element, create a class containing that like this
class mySetAndLast extends Set{
T last;
Set<T> mySet;
}
now the question is what is the 'last element inserted'. Imagine your set was empty
-> insert x -> ok, x is the last inserted
-> insert y (y!=x) -> ok: y is the last inserted
-> insert x -> ?
is now x or y the last inserted?
x does not get inserted because y was the last element inserted and x already is an element of the set, on the other hand x from the user's point of view was the last inserted..
For your own, internal purpose, you could "hack" your own Set from any List implementation:
public class ListSet<E> extends ArrayList<E> implements Set<E> {
#Override
public boolean add(E item) {
return contains(item) ? false : super.add(item);
}
// ... and same for add(int, E), addAll(...), etc.
}
That example is slow (O(n) for an add) but, as you are the one implementing it, you can go back to it with smarter code for contains() based on your specifications.
I'm trying to write an Insertion sort for a LinkedList, I have got a working method but it is incredibly slow. Over an hour to add&sort 50,000 elements.
public void insert(Custom c)
{
int i = 0;
for (i = 0; i < list.size(); i++)
{
if(list.get(i).compareTo(c) > 0 )
{
list.add(i,c);
return;
}
}
list.add(c);
}
I know i could use Collections.Sort but for this assignment I am required to write my own LinkedList. I'm not asking for a full solution just some pointers.
First of all, insertion sort on a List is going to be slow (O(N^2)) ... no matter how you do it. But you appear to have implemented it as O(N^3).
Here is your code ... which will be called N times, to add each list element.
public void insert(Entry e)
{
int i = 0;
for (i = 0; i < list.size(); i++) // HERE #1
{
if(list.get(i).compareTo(e) > 0 ) // HERE #2
{
list.add(i,e); // HERE #3
return;
}
}
list.add(e); // HERE #4
}
At "HERE #1" we iterate up to M times where M is the current (partial) list length; i.e. O(M). This is inherent in an insertion sort. However, depending on how you implemented the size() method, you could have turned the iteration into a O(M^2) sequence of operations. (The LinkedList.size() method just returns the value of a size variable. No problem here. But if size() counted the elements ... )
At "HERE #2" we have a fetch and a comparison. The comparison (compareTo(...)) is cheap, but the get(i) operation on a linked list involves traversing the list from the beginning. That is an O(M) operation. And since you make the get(i) call O(M) times per insert call, this makes the call O(M^2) and the sort O(N^3).
At "HERE #3" the add(i,e) repeats the list traversal of the previous get(i) call. But that's not so bad because you only execute that add(i,e) call once per insert call. So the overall complexity is not affected.
At "HERE #4" the add() operation could be either O(1) or O(M) depending on how it is implemented. (For LinkedList.add() it is O(1) because the list data structure keeps a reference to the last node of the list.) Either way, overall complexity is not affected.
In short:
The code at #2 definitely make this an O(N^3) sort.
The code at #1 could also make it O(N^3) ... but not with the standard LinkedList class.
So what to do?
One approach is to recode the insert operation so that it traverses the list using the next and prev fields, etcetera directly. There should not be calls to any of the "higher level" list operations: size, get(i), add(e) or add(i, e).
However, if you are implementing this by extending or wrapping LinkedList, this is not an option. Those fields are private.
If you are extending or wrapping LinkedList, then the solution is to use the listIterator() method to give you a ListIterator, and use that for efficient traversal. The add operation on a ListIterator is O(1).
If (hypothetically) you were looking for the fastest way to sort a (large) LinkedList, then the solution is to use Collections.sort. Under the covers, that method copies the list contents to an array, does an O(NlogN) sort on the array, and reconstructs the list from the sorted array.
According to this response, you should use ListIterator.add() instead of List.add due to the better performance.
What about using a faster sorting algorithm?
Here is something known as QuickSort. Its way faster then normal sorts for larger data sets. QuickSort has a average case of O(nlogn) while insertion only has a average case of O(n^2). Big difference isn't it?
Sample implementation
QuickSort Class
import java.util.*;
public class QuickSort{
public static void swap(int A[] , int x, int y){
int temp = A[x];
A[x] = A[y];
A[y] = temp;
}
public static int[] QSort(int A[],int L, int U){
Random randomGenerator = new Random();
if ( L >= U){
return A;
}
if (L < U) {
/*
Partion the array around the pivot, which is eventually placed
in the correct location "p"
*/
int randomInt = L + randomGenerator.nextInt(U-L);
swap(A,L,randomInt);
int T = A[L];
int p = L;
for(int i= L+1; i<= U; i++){
if (T > A[i]){
p = p+1;
swap(A,p,i);
}
}
/* Recursively call the QSort(int u, int l) function, this deals with
the upper pointer first then the lower.
*/
swap(A,L,p);
QSort(A,p+1,U);
QSort(A,L, p-1);
}
return A;
}
}
Sample Main
import java.util.*;
public class Main{
public static void main(String [] args){
int[] intArray = {1,3,2,4,56,0,4,2,4,7,80,120,99,9,10,67,101,123,12,-1,-8};
System.out.printf("Original Array was:\n%s\n\n",Arrays.toString(intArray));
System.out.printf("Size of Array is: %d\n\n",intArray.length);
QuickSort.QSort(intArray, 0, intArray.length - 1);
int num = Integer.parseInt(args[0]);
System.out.println("The sorted array is:");
System.out.println(Arrays.toString(intArray));
}
}
The above example will sort an Int array but you can easily edit it to sort any object(for example Entry in your case). Ill let you figure that out yourself.
Good Luck
list.add(e) and list.get(e) will take o(n) each time they are called. You should avoid to use them when you travel your list.
Instead, if you have to write your own linked list you should keep track of the elements you are traveling. by replacing the operation i++ and get(i) by elem = elem.next or elem = elem.getnext(), (maybe something else depending on how you implemented your linked list). Then you add an element by doing:
elem.next.parent = e;
e.next = elem.next;
elem.next = e;
e.parent = elem;
here my example works for a doubly linked list and elem represent the element in the linked list you are currently comparing your object you want to add.
I am creating a partially ordered set as an abstract data type in java, and I have to make an iterator version of the set of numbers, and an iterator for the relations. Now for the elements, I've used HashSet of integer, and for the relations, I've used an ArrayList of pairs (pairs is a class I created that takes 2 ints as parameter which basically is like (x, y)). I need to make 2 iterators, one for s and one for r, but they have to follow a certain ordering,
1. if (x, y) belong to R, then the iterator of s should return x before it returns y
2. if (x, y) and (y, z) belong to R, then iterator of r should return (x, y) before it returns (y, z)
I made a helper method that check first for to check if the element n in the set is the first element in a pair then it returns it, but I cant seem to check if it is second element, how can I check for the first element if it is returned or not?
Here is my code:
private class IntGenerator implements Iterator {
private Iterator<Integer> i;
public IntGenerator () {
i = S.iterator();
}
public boolean hasNext() {
return i.hasNext();
}
public Object next() {
int n = i.next();
for (Pair p : R) {
if (isInFirstElmPair(p, n)) return n;
else (isInSecondElmPair(p, n)) {
// should check for the first element
// if it was returned or not
}
}
}
public void remove() { throw new UnsupportedOperationException(); }
}
I would really appreciate any kind of help, or hint in this code.
Thanks
EDIT:
Okay, I've wrote the code to it after adding a new set which will hold the returned elements, and this is what I wrote:
Set<Integer> returnedNumbers = new HashSet<Integer> ();
public Object next() {
int n = i.next();
for (Pair p : R) {
if (isInSecondElmPair(p, n)) {
if (returnedNumbers.contains(p.getFirstElm())) {
returnedNumbers.add(n);
return n;
}else{
returnedNumbers.add(p.getFirstElm());
return p.getFirstElm();
}
}else{
returnedNumbers.add(n);
return n;
}
}
}
Is this code correct? Also, eclipse seems to give me an error telling me I need to return a value outside the loop, but I already returned inside for every case why does it need more?
Appreciate the help
Well, to check if a value was previously returned, you of course need to keep track of all values that were returned previously.
So in your iterator, you could define
Set<Integer> previouslyReturned = new HashSet<Integer>();
and then, before returning it in your for loop, add it there:
if (isInFirstElmPair(p, n)) {
previouslyReturned.add(n);
return n;
}
else (isInSecondElmPair(p, n)) {
if (previouslyReturned.contains(n) {
// do one thing
} else {
// do another thing
}
}
This way, however, you are constructing a set of s in the order in which it shall be returned inside the iterator. It would make sense to create this once (consider a LinkedHashSet), keep it somewhere else and iterate over it.
Generally I am not sure that this approach will lead to what you want. Do you know anything about theorder of elements in S and R? If the iteration order is arbitrary (i.e. because relations were added in unpredictable order) then the iterator will first return the first half of the first relation pair, even if that element is in the second half of another pair. Do you have to use an element HashSet and a relation List?
I'm using a custom LinkedList class that goes like this:
public class LinkedList {
// Get and Set methods are NOT necessary!
private LinkedList next;
private final String word;
public LinkedList(String word, LinkedList next) {
this.word = word;
this.next = next;
}
Now my task is to write a method that takes an array of Strings, and coverts each string object into a LinkedList WITHOUT loops, so using recursion. How can this be done without loops? This is unimaginable to me. Where do I begin?
Edit: Let me clarify that the function I'm supposed to write only takes one argument, which is an array of Strings, and returns a LinkedList..
enter code here
public LinkedList arrayToLinkedList(String[] myArray)
{
String[] toConvert = myArray;
List<String> toConvertList = (List) Arrays.asList(toConvert);
LinkedList<String> convertedLinkedList = new LinkedList<String>(toConvertList);
return convertedLinkedList;
}
Probably just me, but I don't like any of the solutions provided.
/**
* Creates linked list from array input.
*
* #param input
* data array
* #return linked list with data
*/
public static LinkedList Of(String[] input) {
// Checks if array has elements.
if (input == null || input.length < 1)
return null;
// Starts creating the array using overload 2.
return LinkedList.Of(input, 0);
}
/**
* Creates linked list from array input (overload 2).
*
* #param input
* data array
* #param i
* counter to remember at what element is current
* #return linked list with data
*/
public static LinkedList Of(String[] input, int i) {
//Tests if counter is within array elements.
if (input.length - 1 > i)
// Returns new element with (current element data, reference
// to next element). Note that next element will be returned
// by this same method (this is why it is recursive).
return new LinkedList(input[i], LinkedList.Of(input, i + 1));
//Last element. From here backtracking will begin.
return new LinkedList(input[i], null);
}
Here is something else:
public String toString() {
StringBuilder sb = new StringBuilder(this.word);
LinkedList tmp = this;
while (tmp.next != null) {
sb.append(" > ");
tmp = tmp.next;
if (tmp.word != null)
sb.append(tmp.word);
}
return sb.toString();
}
And to test:
String str = "Neque porro quisquam est qui dolorem ipsum quia "
+ "dolor sit amet, consectetur, adipisci velit...";
LinkedList ll = LinkedList.Of(str.split("\\s+"));
System.out.println(ll);
I'm not sure what language you are using, but here's a general idea:
public LinkedList myfunction(String arr[]) {
if(arr.empty == true)
return void;
//return the array minus the first element
String shorterarray[] = substr(arr[],1);
//recursively create the next element
LinkedList myItem = new LinkedList(arr[0], myfunction(shorterarray[]));
}
You'll have to do the subtring and boundary checking in whatever language you are using.
How about:
public static void main(String[] args) {
String[] data = new String[] { "1", "2", "3" };
LinkedList head = build(data);
while (head != null) {
System.out.println(head.word);
head = head.next;
}
}
private static LinkedList build(String[] data) {
if (data == null || data.length == 0) {
return null;
}
LinkedList head = new LinkedList(data[0], null);
build(head, data, 1);
return head;
}
private static LinkedList build(LinkedList node, String[] data, int index) {
if (index == data.length) {
return node;
}
node.next = build(new LinkedList(data[index], null), data, ++index);
return node;
}
private static class LinkedList {
private final String word;
private LinkedList next;
public LinkedList(String word, LinkedList next) {
this.word = word;
this.next = next;
}
}
To add, it might also be worth while pointing out that creating collections with recursion is really bad in practice - it can easily blow out your stack size.
First, anything you can do with iteration (looping) you can do with recursion, and vice-versa (though without tail-call elimination, something Java doesn't have, recursion is often more expensive than iteration).
When trying to figure out how to solve a problem recursively you want to figure out how to break off one or more pieces of the problem that look like the same sort of problem but only smaller. With list problems that often means that when given an n element list you want to recursively handle n-1 elements. You also need to have a base case so the recursion will terminate. With lists the base case is usually a list of 0 elements.
An array is a lot like a list, but Java arrays don't have slicing (ie: you can't pass around just a piece of an array) so you'll want a helper method that knows which piece of the array we care about:
private static LinkedList fromArray(String[] a, int offset) {
Since your LinkedList class breaks down into a word and then the tail part of the list (pointed to by next) it makes sense for us to also deal with the tail part of the input array. The offset parameter lets us know how much of the tail part of the array we'll be looking at: it's the first index we care about.
The public method will just call the helper method giving it an offset of 0:
public static LinkedList fromArray(String[] a) {
return fromArray(a, 0);
}
An offset of 0 means we care about element 0 (the first element) and every element after it.
So now to write the "helper" method, which is where all of the real work is done.
First, get the base case out of the way. The base case is where the part of the array we're converting is empty. That would be the case if offset >= a.length. In that case we want to return an empty LinkedList, which is actually represented by null. So return null in that case.
Once the base case is taken care of, think about the recursive case. We have one or more elements in the part of the array we care about. Let's create a LinkedList to hold the first of those elements, a[offset]. (The first element we care about, that is. Recall that the helper only cares about the part of the array starting at offset up to the end.) The rest of the elements can be handled by calling ourselves passing in the same array, but incrementing offset by one, as we don't want the recursive call to handle the element we already handled.
Call a function that takes three arguments; a source array, a current position in the array, and a destination linked list.
Does that get your head going/can you figure it out from there?
Try this:
private LinkedList formlist(LinkedList list, String[] str, int length, int i) {
if(i==length)
return list;
return formlist(new LinkedList (str[i],list),str,length,i+1);
}
Ok, since there is the requirement for a single method with String[] args.
here is a java example. (based on a previous answer but converted to java)
private LinkedList build(String arr[]) {
if(arr.length == 0)
return null;
//return the array minus the first element
String shorterarray[] = Arrays.copyOfRange(arr, 1, arr.length);
//recursively create the next element
return new LinkedList(arr[0], build(shorterarray));
}
I have this program where it have some recursive function similar to this:
public static void lambda(HashSet<Integer> s){
if(end(s)){
return;
}
for(int i=0;i<w;i++){
HashSet<Integer> p = (HashSet) s.clone();
p.addAll(get_next_set());
do_stuff_to(p);
lambda(p);
}
}
What I'm doing is union every set with the set s. And run lambda on each one of the union.
I run a profiler and found the c.clone() operation took 100% of the time of my code. Are there any way to speed this up considerably?
When you are cloning, what are you really trying to do, maybe you don't need to do a complete cloan?
Your best bet at improving the performance of your lambda function is to extend HashSet and overide the clone definition with a custom one that is particular to your situation...
I don't know of anyother way to really help with out more information unfortunatly.
If I get it right you try to do the following:
lambda(Set p) {
lambda(p + further elements);
}
You can avoid cloning p e.g. by reimplementing a list and using the Nodes as parameters for lambda:
class Node {
int content;
Node next;
Node(int content, Node next) {
this.content = content;
this.next = next;
}
}
void lambda(Node set) {
// add new elements to front
Node newSet = set;
for(Integer i : new_elements() ) {
newSet = new Node(i, newSet);
}
lambda(newSet);
// Observe that set is not modified by adding new elements
}
This is a low-level-solution and you would have to implement a slow sequential search/find-algorithm (if you rely on unique elements in the set), yet in my experience such a stack is a good solution for most recursive algorithms.
This is what I did to speed up everything, this way I never have to create new sets.
public static void lambda(HashSet<Integer> s){
if(end(s)){
return;
}
ArrayList<Integer> diff = new ArrayList<Integer>();
for(int i=0;i<w;i++){
//an array version of the next set, it is pre-computed
int[] a = get_next_set_array();
for(int j=0;j<a.length;j++){
if(!s.contains(a[j])){
diff.add(a[j]);
}
}
s.addAll(diff);
do_stuff_to(s);
s.removeAll(diff);
diff.clear();
lambda(p);
}
}
On average this is much faster, and the program spend roughly the same amount of time on the addAll and removeAll.