How to remove from an immutable linked list? - java

I need to make a linked list using a remove() method, which takes a parameter, e, a generic stand in, and removes the linked node which contains e, then the method returns a new Linked list containing all elements except e.
I have no idea how to implement this and the farthest I have gotten is this:
public Set<E> remove(E e) {
LinkedNode<E> current = null;
if(!this.contains(e)) {//if this list doesnt contain e, return this
return this;
} else {//otherwise go through this set and if it contains e return new set w/out it
for(E j:this) {
if(j.equals(e)) {
current = new LinkedNode<E>(j,current);
}
}
}
Set<E> newSet = new LinkedSet<E>(current);
for(E i:newSet) {
System.out.print(i +", ");
}
return newSet;
}
this code uses an iterator so the enhanced for loop works, but it returns sets with the wrong info. I think this might be because the tail end of the new set I want still has the link to the end of the old list, but this is just a guess.
The last output I got was:d, b, a, c, e, b, d, a, c, e, b, d, a,
and the input was:c,a,d,b,e
I was trying to remove c

Assuming you are returning remaining elements from remove() method you can add every element which is not e:
public Set<E> remove(E e) {
Set<E> newSet = new LinkedSet<E>();
for(E j : this) {
if (!j.equals(e)) {
newSet.add(j);
}
}
return newSet;
}

Assume that there are no dublicates in your list (because actually return type is a set) or at least we need to remove only first occurency.
We could copy elements of current list to new list before 'e' position and use elements after 'e' as tail for both lists. In this way we would copy just part of list, there will be shared elements now. For immutable collection it's ok, but you need be careful with other LinkedList methods implementations.
public Set<E> remove(E e) {
if (!this.contains(e)) {
return this;
}
final LinkedNode<E> head = new LinkedNode<E>(this.head);
// Copy elements of current list to new list before 'e' position
LinkedNode<E> current = this.head, newListCurrent = head;
while (!e.equals(current.next)) {
newListCurrent.next = new LinkedNode<E>(current.next);
newListCurrent = newListCurrent.next;
current = current.next;
}
// Now current.next is element to remove. Link tail of new list to tail of current list
newListCurrent.next = current.next.next;
return new LinkedList<E>(head);
}
It's like pseudocode, but i need full code of your LinkedList and LinkedNode to use them correctly. I've not enought reputitation to ask about it in comment ))

Related

Why LinkedList clone method implementation needs to store the copyied list into virgin state?

public Object clone() {
LinkedList<E> clone = superClone();
// Put clone into "virgin" state
clone.first = clone.last = null;
clone.size = 0;
clone.modCount = 0;
// Initialize clone with our elements
for (Node<E> x = first; x != null; x = x.next)
clone.add(x.item);
return clone;
}
This is the source code of LinkedList. The clone already has the elements in the original list, what is the purpose of making it empty and assigning the elements again?
The way that a java.util.LinkedList is implemented, is that it uses Node<E> objects to link elements together. And a LinkedList object has a reference to the first and last Node<E> in the list.
If you scroll around a bit you'll find this declaration:
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
Visually, a LinkedList with 4 elements can be thought of like this:
When cloning a linked list, what we would expect to happen is that the entire chain of Nodes is copied. Like this:
However, superClone just calls super.clone, which does not make copies of these Node objects. It only copies the LinkedList object. Therefore, it would be incorrect to implement LinkedList.clone by just calling super.clone, because then the cloned list would use the same chain of Nodes as the original:
This would mean that adding something in the middle of the chain would add that thing to both the cloned list, and the original list!
By resetting the cloned list to its initial state, and then re-adding all the elements from the original list, we create a new chain of Node objects for the cloned list. This is because add creates new Node objects:
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
The purpose of the clone method is returning a copy of the instance object. They correct meaning of copy is delegated to the implementor class, but main requirement is when
object.clone() != x, it returns true.
In the case of the Java LinkedList, it returns a shallow copy of the elements, but not a copy of the elements theirslef. In this case the list.clone() != list, it's still true, but when you check their elements is going to return false (example list.get(0) != list.clone().get(0)).
The purpose of the copied list is to be not linked to the original one, so you could add/insert/delete elements without modify the original list.
Example (pseudo-code):
original.add(1);
original.add(2);
original.size(); // 2
clonedList = original.clone();
clonedList.size(); // 2
clonedList.add(3);
clonedList.size(); //3
originalList.size(); //2

How can I display which elements were removed from list in custom OrderedLinkedList class?

I am implementing a custom Ordered LinkedList class with a nested Ordered ListNode class. Everything is working fine, but I am trying to expand on it by accessing the elements that are removed.
This is not a requirement, but I am curious how this would work since I can only use the methods I was instructed to create, which are boolean add(), boolean remove(), and clear().
I am also keeping track of each modification, which is incremented with each successful addition, removal, or call to clear(). I can simply create another OrderedLinkedList, and add the removed elements to it, but I feel like I'm adding an unnecessary modification count.
Again, this part is just for fun and not required. I feel this will give me a deeper understanding of creating custom classes.
I'll show the remove and main methods. The remove method signature cannot be changed.
public boolean remove(Comparable obj) {
for(OrderedListNode element = head.next; element != tail; element = element.next) {
if(obj.equals(element.dataItem)) { //if element being removed is at the cursor
OrderedListNode previousNode = element.before;
OrderedListNode nextNode = element.next;
nextNode.before = previousNode; //places next element that's after before to the element after current element [prev -> current -> next]
previousNode.next = nextNode; //places prev of next element to the element before current
element.dataItem = (Comparable)NOT_FOUND; //removed element is now null
modCount++; //another modification
theSize--; //reduce the size by 1
return true; //if remove is successful
}
}
return false; //otherwise, not successful removal
}
Main method:
public static void main(String[] args) {
OrderedLinkedList list = new OrderedLinkedList();
OrderedLinkedList removedList = new OrderedLinkedList();
modCount = 0;
list.add("Dog");
list.add("Bird");
list.add("dog");
list.add("bird");
list.add("Cat");
System.out.println("Before removal of element");
System.out.println(list);
list.remove("Dog");
removedList.add("Dog"); //not what I'm wanting to do
System.out.println("Removed " + removedList);
System.out.println("After removal of element");
System.out.println(list);
System.out.println("Total modifications = " + modCount);
System.out.println();
}
Output:
Before removal of element
Bird, Cat, Dog, bird, dog
Removed Dog //not actually accessing the element originally removed. just printing a new list
After removal of element
Bird, Cat, bird, dog
Total modifications = 7 //unnecessary modification due to additional add
If you just want to store the elements that you have removed without increasing your modification count, you can use ArrayList and put your removed elements into it. This way your modification count will not be impacted.
You can store the removed values by implementing an additional pop method. The return type should be Comparable and when the object to be removed found, store it in a temporary object and return that, instead of returning a boolean true. When the object is not found, simply return null.
If the Comparable object is found which is to be removed, the method will return that object so that you can store it. If not, a null will return so that you can use an if-check for the pop method to get that if remove is successful or not.
Here is a sample method I've just written for you;
Sample Pop Method
public Comparable pop(Comparable obj) {
for (OrderedListNode element = head.next; element != tail; element = element.next) {
Comparable temp = null; // declaration of the temporary object
if (obj.equals(element.dataItem)) { // if element being removed is
// at the cursor
temp = obj; // store obj in temp
OrderedListNode previousNode = element.before;
OrderedListNode nextNode = element.next;
nextNode.before = previousNode; // places next element that's
// after before to the element
// after current element [prev
// -> current -> next]
previousNode.next = nextNode; // places prev of next element to
// the element before current
element.dataItem = (Comparable) NOT_FOUND; // removed element is
// now null
modCount++; // another modification
theSize--; // reduce the size by 1
return temp; // if remove is successful
}
}
return null; // otherwise, not successful removal
}
Test Demo
Your test code should be like this;
public static void main(String[] args) {
OrderedLinkedList list = new OrderedLinkedList();
OrderedLinkedList removedList = new OrderedLinkedList();
modCount = 0;
list.add("Dog");
list.add("Bird");
list.add("dog");
list.add("bird");
list.add("Cat");
System.out.println("Before removal of element");
System.out.println(list);
// list.remove("Dog"); // not needed anymore
// removedList.add("Dog"); //not what I'm wanting to do
// pop returns the removed object
removedList.add(list.pop("Dog"));
System.out.println("Removed " + removedList);
System.out.println("After removal of element");
System.out.println(list);
System.out.println("Total modifications = " + modCount);
System.out.println();
}

Deleting and adding objects to list while iterating

I am trying to remove objects from a list and I get the following exception :
failure:java.util.ConcurrentModificationException null
And this is how I try to remove the objects from the list:
private List<testVO> removeDuplicateEntries(List<testVO> sessionList,List<testVO> dbList){
for (Iterator<testVO> dbIterator = dbList.listIterator(); dbIterator.hasNext(); ) {
testVO voDB = dbIterator.next();
for (Iterator<testVO> sessionIterator = sessionList.iterator(); sessionIterator.hasNext();) {
testVO voSession = (testVO) sessionIterator.next();
if(voDB.getQuestionID().intValue() == voSession.getQuestionID().intValue()){
//remove the object from sesion list
sessionIterator.remove();
//Add the object from DB to session list
sessionList.add(voDB);
}
}
}
return sessionList;
}
I would like to remove the duplicates which are currently in sessionList and add the ones from dbList.
You cannot add to the sessionList on iterating through it.
for (Iterator<testVO> dbIterator = dbList.listIterator(); dbIterator.hasNext(); ) {
testVO voDB = dbIterator.next();
List<testVO> toBeAdded = new LinkedList<>();
for (Iterator<testVO> sessionIterator = sessionList.iterator(); sessionIterator.hasNext();) {
testVO voSession = (testVO) sessionIterator.next();
if(voDB.getQuestionID().intValue() == voSession.getQuestionID().intValue()){
//remove the object from sesion list
sessionIterator.remove();
//Add the object from DB to session list
//CANNOT DO: sessionList.add(voDB);
toBeAdded.add(voDB);
}
}
Collections.addAll(sessionList, toBeAdded);
}
List<testVO> toRemove = ...
List<testVO> toAdd = ...
// in loop
toRemove.add(removed);
toAdd.add(added);
//after appropraite loops
yourList.addAll(toAdd);
yourList.removeAll(toRemove);
the toRemove is added here in case one is using for-each version of the for loop; it is better to remove an element from collection through iterator, since it does not consume any more resources for searches.
As was explained in other answers, you can't add to the collection while iterating it. You have to do the modification of information using the iterator itself - or wait until you finish iterating.
However, a plain Iterator just allows you to remove items. Using a ListIterator you can also add to the list. Thus, if you use sessionList.listIterator() rather than sessionList.iterator(), you'll be able to add the item while you iterate.
This has a different result than adding to the list (if that was possible), though. Suppose you have a list:
[ A, B, C, D, E ]
And you wanted to replace C with c and D with d. If you use the list iterator, your result will be:
[ A, B, c, d, E ]
While adding the items to the list would result in:
[ A, B, E, c, d ]
So, if you want the items to be appended to the end, you should do as other answers have pointed, collect all the items you want to add, and addAll when you finish iterating sessionList.
But if you want to replace them in place ([ A, B, c, d, E ]), you can use the list iterator:
for (ListIterator<testVO> sessionIterator = sessionList.listIterator(); sessionIterator.hasNext();) {
testVO voSession = (testVO) sessionIterator.next();
if(voDB.getQuestionID().intValue() == voSession.getQuestionID().intValue()){
//remove the object from sesion list
sessionIterator.remove();
//Add the object from DB to the session list
sessionIterator.add(voDB);
}
}
The differences is that sessionIterator is now declared as a ListIterator and initialized with sessionList.listIterator(), and also that instead of sessionList.add() you are using sessionIterator.add().
Note that the add operation on ListIterator is optional, so, depending on the list implementation, this method may not work and throw an UnsupportedOperationException.

Non-destructive recursive intersect of two singly linked lists

I want to take two singly linked lists (this function is called from within one) and create a third singly linked list that contains all intersections between the two. So if p=[0,1,2,3] and q=[1,3,7,9] then out=[1,3], while leaving the old lists intact.
As you can see I need to declare "out" in two places. But if I hit the declaration by calling the function again, it naturally wipes what I previously wrote to it. I really can't figure out how to avoid it.
Singly linked lists can be generated with http://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html . first is my header.
public List intersection(List l) {
if(first.data == l.first.data) {
List lTail = new List(l.first.next);
List tail = new List(first.next);
List out = new List(new Node(first.data, null)); //Bad idea #1
// System.out.println(out);
return tail.intersection(lTail);
} else if (first.data > l.first.data && l.first.next != null) {
List lTail = new List(l.first.next);
return intersection(lTail);
} else if (first.data < l.first.data && first.next != null) {
List tail = new List(first.next);
return tail.intersection(l);
} else { //When both lists are at the end position
List out = new List(new Node(0, null)); // Bad idea #2
return out;
}
}
List<T> p = new LinkedList<T>();
p.add...
...
List<T> q = new LinkedList<T>();
q.add...
...
List<T> intersection = new LinkedList<T>(p);
intersection.retainAll(q);
Now intersection contains only elements, which are in both lists, while lists theirselves remain untouched.

How do I reverse the order of this implementation of a Linked List?

I have a class called LinkStrand which functions very similarly to a Linked List. It has toString(), size(), append(), next(), and value(), but NOT a previous() method. I am trying to write code that reverses the order of the nodes, as well as the string within each node. In order to make it easier on myself in a few of the other methods I've had to write, I got rid of the next node requirement in constructing a node. Here's what the Node class looks like:
private class Node {
public Node myNext;
public String myData;
Node(String value) {
myData = value;
//myNext = next;
}
}
My .reverse() method currently reverses all of the strings within the nodes individually, but does not reverse the order of the nodes themselves. It is copied below:
public IDnaStrand reverse() {
if (this == null)
return this;
Node prevStrand = null;
Node thisStrand = myHead;
String revString;
LinkStrand val = new LinkStrand();
while (thisStrand != null){
Node hold = thisStrand.myNext;
if (revSave.containsKey(thisStrand.myData)){
revString = revSave.get(thisStrand.myData);
val.append(revString);
//System.out.println("Val is: " + val);
}
else{
revString = reverseStr(thisStrand.myData);
val.append(revString);
//System.out.println("Val is: " + val);
revSave.put(thisStrand.myData, revString);
}
thisStrand.myData = revString;
thisStrand.myNext = prevStrand;
prevStrand = thisStrand;
thisStrand = hold;
}
return val;
}
I've been trying to come up with some kind of way to reverse the node order, but I'm drawing a blank. Does anyone have any idea how I might go about it?
Thanks!
If you are allowed to modify IDnaStrand and LinkStrand, add a method prepend(Node n). Then, as you iterate through the list, just prepend each node.
If you can't modify your classes, save the Nodes to an array in reverse order (nodeArray[size-1], nodeArray[size-2], ...) then create a new LinkStrand going through the array in order. Alternatively you could load the array in order, then create the LinkStrand in reverse order.
example:
thisStrand = myHead;
int size = 0;
while(thisStrand != null){
thisStrand = thisStrand.myNext;
size++;
}
Node[] nodeArray = new Node[size];
thisStrand = myHead;
for(int i = size-1, i < 0; i--) {
nodeArray[i] = thisStrand;
}
Now you have the array, just load it into a new list! Of course adding a prepend method would be better, just have the class do
newElement.myNext = MyHead;
MyHead = newElement;
Create a new instance
loop through the original and insert into the new instance at position 0, then return it.
Other way would be to sort it, but can't see anything in your question that would indicate it is currently sorted.
Let's say your list looks like this:
A -> B -> C -> D -> E
I'll shorten the notation because I'm going to write this a lot:
A B C D E
Let's take 3 variables. I'll show their whole lists, so you can see what is going on. The first item is always the node stored in one of the variables
list: null
curr: A B C D E
next: B C D E
Set A's next-pointer to the value of list (null). It's now the end of the list.
list: null
curr: A
next: B C D E
Now, move to the next:
list: A
curr: B C D E
next: C D E
You can see what's going to happen. Continue as we started: set the next-pointer of curr to list:
list: B A
curr: B A
next: C D E
Advance:
list: B A
curr: C D E
next: D E
Again:
list: C B A
curr: C B A
next: D E
And so on...
Pseudocode is rather simple:
list = null
curr = original_list
while next != null
next = curr->next
curr->next = list
list = curr
curr = next
end
All this is really doing is taking each node from the head of the list and making it the head of the other list. This has the effect of reversing the order. My answer is perhaps a little long-winded, but that's all you do.

Categories