Need to remove duplicate nodes in linked list - java

I am attempting to write code that will remove the duplicate nodes in a singly-linked list. The duplicates removed are only removed until the number stored in the next node changes.
For example, if the input list is [ 0 0 0 0 1 1 0 0 0 3 3 3 1 1 0 ],
the output list is [ 0 1 0 3 1 0 ].
I have attempted to write the code and tried multiple things. Each time when I call the function it either returns the original linked list or just the original head and original tail.
I attempted creating a temporary linked list and storing values in that list but it does not return properly.
My latest attempt is in the code snippet below and only returns the head and tail of the original list.
My question is, how I should proceed with this code? I tried to draw it out and visualize it but it did not help.
I am not looking for code to be written just a push in the correct direction.
I think that the code I have now is a dead end and I may have to restart from scratch.
What is the best way to start to implement this code to achieve an answer?
public void squish() {
SListNode current = head;
SListNode iterator = current.next;
while (iterator != null){
if (current.equals(iterator)){
iterator = iterator.next;
} else {
if (current.next.equals (null)) {
break;
} else {
head.next = iterator;
current = iterator;
}
}
}
}

In your current solution you are trying to do 2 things at once, skipping n equal numbers and re-arranging your list. This makes the solution a bit more complex than necessary.
What you can do is looping while you have a current node and that current node is followed by another.
now within the loop you have 2 possibilities;
either the values of current and next are equal, in that case make the node following current (next) the same as the one following the current next.
or the values are unequal, in that case walk the list by setting the current node to its follower node.
That's it, no explicit assignments to the head reference should be necessary.

I'm guessing that this is homework, so I don't want to give a complete solution.
Working directly with iterators is always tricky. Instead of working in place with a single List, you should consider creating a new List with the solution you want. e.g., schematically...
Create a new empty List for the result
Initialize prevValue
Loop over the values in input list
If the value is not equal to the prevValue
add it to the result list
update prev value
Of course, if the class/assignment really wants you to use iterators, ignore the above...

public void RemoveDuplicates()
{
Dictionary<int, int> myDict = new Dictionary<int, int>();
Node cur = head;
myDict.Add(head.Data, 1);
while (cur.Next != null)
{
if (myDict.ContainsKey(cur.Next.Data))
cur.Next = cur.Next.Next;
else
{
myDict.Add(cur.Next.Data, 1);
cur = cur.Next;
}
}
}

Related

How to do a selection sort with linked list

I think I have the basic idea down for the selection sort, but for some reason it's not working and I don't know why? Anyone have an idea what is wrong here?
A few pointers:
.getValue() just returns the object in the node, I'm using integers.
Node tempNode = new Node(null,null,node.getValue()), the first null is for previous and the second null is for next and the third just sets the object in the node which is integers in this case.
My input is:
9
5
8
6
10
4
My output is this. For some reason it keeps setting 4 over and over again:
4
5
5
4
4
4
public void SelectionSort()
{
Node<T> node2;
Comparable temp;
Node<T> Nodemin;
for(Node<T> node = front;node != null; node = node.getNext())
{
Nodemin = node;
for(node2 = node.getNext();node2 != null; node2 = node2.getNext())
{
temp = node.getValue();
if(temp.compareTo(node2.getValue()) > 0)
{
Nodemin.setValue(node2.getValue());
}
Nodemin = Nodemin.getNext();
}
System.out.println(Nodemin.getValue());
Node<T> tempNode = new Node(null,null,node.getValue());
node.setValue(Nodemin.getValue());
Nodemin.setValue(tempNode.getValue());
}
}
When you are saying Nodemin = Nodemin.getNext();, you are pointing the item to be swapped (the selected item) at the spot beyond where your minimum is. This has an unwanted side effect that when you do the swap, the number you are putting later in the list is going in one beyond the one with which you are swapping it, I believe.
But there is a more subtle flaw in setting Nodemin's value at all as you keep heading down the list and finding lower numbers. Because Nodemin points at a particular location, each time you find a new lowest element, you are not just changing Nodemin's value, but also the value of an item in the list, since they point the same place.
I think you can solve both these problems by changing Nodemin to two separate things, each of which does what you want.
Let minValue be like your temp, tracking the minValue only. Let minLocation always point to where the minValue is (not doing that next line on it ever, just resetting it to where you find a new min).
Then when outside the inner for loop and doing your swap, do it on the place pointed to by minLocation and with the value minValue.
That should fix it. Or it should also work to replace
if(temp.compareTo(node2.getValue()) > 0)
{
Nodemin.setValue(node2.getValue());
}
Nodemin = Nodemin.getNext();
with
if(temp.compareTo(node2.getValue()) > 0)
{
Nodemin = node2;
}
The suggestions to trace through and debug are good ones. You would see evidence of what I am saying, I believe, and catch any mistakes I am making.

Linked List Implementation using dummy nodes

I am working on a project where i have to union and intersect two sets. I am using Linked list for each set with dummy nodes. This is how i initialize my Sets LL class
public Set() {
top = new Node(Integer.MIN_VALUE, new Node(Integer.MAX_VALUE, null) );
} //end Set
And this is how i insert items.
public void insert(int item) {
Node prev = top;
Node curr = top.next;
while( curr.item < item ) {
prev = curr;
curr = curr.next;
}
prev.next = new Node( item, curr);
size++;
} // insert
Now i am finding it hard to get a union or intersection of two sets.
This is what i have in mind for intersection.
public Set intersection( Set setB ) {
Set setC = new Set ();
//loop over both sets and if both have same value add it otherwise
// get to the next node in both sets.
My question is, am i logically correct with the intersection pseudocode? My union pseudocode is laughable though. Can anyone please guide me though this problem?
Your idea will fail for this simple input:
1 2
2 3
Your idea:
//loop over both sets and if both have same value add it otherwise
// get to the next node in both sets.
First iteration - we have 1 and 2, not same value, so we get to the next in both sets
Second iteration - we have 2 and 3, not same value, so get to next
End
What you actually need is:
On mismatch, advance only the list with lower element
On match, add to result and advance both (or to remove duplicates, keep advancing both as long as the same value is repeating)
For union, the idea is very similar:
On mismatch, add the lower one and advance the list that contained the lower element
On match, add and advance both (or keep advancing both as long as the same value is repeating)

How does this void function for deleting a duplicate linkedlists accomplish anything? Parameter passing in Java

So I'm looking through problems in Gayle Lackermaan's Cracking the Coding Interview, and came upon this question:
Write code to remove duplicates from an unsorted linked list
The solution is this
public static void deleteDups (LinkedListNode n){
Hashset<Integer> set = new HashSet<Integer>();
LinkedListNode previous = null;
while(n!=null){
if(set.contains(n.data){
previous.next = n.next;
} else {
set.add(n.data);
previous = n;
}
n = n.next;
}
}
I don't understand the point of previous; The scope of previous is within the function, since it is created inside the function, right? It isn't being used for anything, so why is it there? Also, previous doesn't seem to be moving forward; instead isn't it just being overridden with every iteration?
Also, if I understand Java's passing by value reference style, passing a head node n into a function that does n = n.next a bunch of times will not affect the value of n after it returns right? What if the function did a bunch of n.next = n, or n.data = 3? Would that affect the value of n after it returns? (I assume yes)
I've looked this function for a long time, and I still don't see how calling it will do anything.
This line right here:
previous.next = n.next;
There's magic there, that I'd want to smack a beginning programmer for not documenting. "Previous" is the last item in the linked list we saw. n is the current item. So when we set previous.next to n.next, we are skipping over n. This line effectively removes n from the linked list. It's inside a conditional to check if we've seen that data before, so this is the magic that removes the duplicate.
The reason we're keeping track of previous here is to do that -- link the last thing to the next thing, effectively cutting out the current thing.
How can you state It isn't being used for anything, so why is it there?
See the below...
if(set.contains(n.data){
previous.next = n.next; // used here
} else {
set.add(n.data);
previous = n; // used here
}
previous is used to hold the reference to the "previous" node in the list to the current node in case the current node must be removed. This is done by pointing the "previous" node to the next node instead of the current node.
There is no need to change the passed reference because the first element in the list can never be a duplicate. Therefore you only need to remove nodes after the first node. This is done by manipulating "next" nodes in the list not the "root"

JAVA - sorting a linked list by descending order

i tried to write a method that sort a linked list.
this is java training for me.
the method should get a linked list with values and sort it with selection sort.
but not the usual selection sort, but selection sort that find the biggest number and put it in the start of the linked list. until the list is sorted.
i tried follow the debugger but, i cant really understand what i did wrong.
this is what i tired:
public IntList selectionSort()
{
IntNode tempMax = _head;
IntNode current = _head;
IntNode fromHere = null;
IntNode toHere = _head;
IntNode prev = null;
while(toHere != null)
{
current = toHere;
tempMax = toHere;
while (current != null)
{
if (current.getNext() != null && current.getNext().getValue() > tempMax.getValue())
{
prev = current;
tempMax = current.getNext();
current = current.getNext();
}
else current = current.getNext();
}
prev.setNext(prev.getNext().getNext());
tempMax.setNext(toHere);
if (fromHere == null)
_head = tempMax;
else fromHere.setNext(tempMax);
fromHere = tempMax;
toHere = fromHere.getNext();
}
return this;
}
A few tips:
If you want the smallest number then current.getNext().getValue() > tempMax.getValue() should have a > instead of a <
Your code will also fail if the first element is already the minimum value, as you try to do something to null
I can see duplicated code in here too, current = current.getNext(). Pointer operations are generally hard to code, and writing clearer code sticking to the principle of Don't Repeat Yourself will probably help you see bugs!
It will help people here help you if you print compiler/runtime error messages
The main issue with your code, is that it misbehave when a node is already at the position it should be. If we execute with :
5 -> 1 -> 2 -> 3-> 4
prev will be null and we crash.
If we do with :
1 -> 4 -> 5 -> 3-> 2
at the first iteration you obtain
5 -> 4 -> 1 -> 3-> 2
So far so good.And then, after the loop of the second iteration
5 -> 4 -> 3-> 2 // prev still pointing at 4, 1 dissapears
5 -> 4 -> 4. // tempMax = toHere so tempMax->tempMax, and the other elements are gone
So the manifestation is that prev is invalid in some way.
There is a quick fix, like skipping the repositioning when toHere is the maximum,
but quick fixes are not what you need. You should :
Rethink about some special cases. Empty list, one element, list already sorted, list sorted in reverse, random order, (duplicate element??)
Write unit test for each case
Rewrite your algorithm, and avoid Oh yes, I forgot the case... . Dumb it down, you only need to replace the first element at each given step with the maximum found at this step.
Avoid variables which have redundant information. For example, tempMax should always be the next of prev, so prev alone is enough. Otherwise you are spending brain cells preserving consistency.
Test again the suite case.

What is an efficient algorithm to find whether a singly linked list is circular/cyclic or not? [duplicate]

This question already has answers here:
How to detect a loop in a linked list?
(29 answers)
Closed 5 years ago.
How can I find whether a singly linked list is circular/cyclic or not? I tried to search but couldn't find a satisfactory solution. If possible, can you provide a pseudo-code or Java-implementation?
For instance:
1 → 3 → 5 → 71 → 45 → 7 → 5, where the second 5 is actually the third element of the list.
The standard answer is to take two iterators at the beginning, increment the first one once, and the second one twice. Check to see if they point to the same object. Then repeat until the one that is incrementing twice either hits the first one or reaches the end.
This algorithm finds any circular link in the list, not just that it's a complete circle.
Pseudo-code (not Java, untested -- off the top of my head)
bool hasCircle(List l)
{
Iterator i = l.begin(), j = l.begin();
while (true) {
// increment the iterators, if either is at the end, you're done, no circle
if (i.hasNext()) i = i.next(); else return false;
// second iterator is travelling twice as fast as first
if (j.hasNext()) j = j.next(); else return false;
if (j.hasNext()) j = j.next(); else return false;
// this should be whatever test shows that the two
// iterators are pointing at the same place
if (i.getObject() == j.getObject()) {
return true;
}
}
}
A simple algorithm called Floyd's algorithm is to have two pointers, a and b, which both start at the first element in the linked list. Then at each step you increment a once and b twice. Repeat until you either reach the end of the list (no loop), or a == b (the linked list contains a loop).
Another algorithm is Brent's algorithm.
Three main strategies that I know of:
Starting traversing the list and keep track of all the nodes you've visited (store their addresses in a map for instance). Each new node you visit, check if you've already visited it. If you've already visited the node, then there's obviously a loop. If there's not a loop, you'll reach the end eventually. This isn't great because it's O(N) space complexity for storing the extra information.
The Tortoise/Hare solution. Start two pointers at the front of the list. The first pointer, the "Tortoise" moves forward one node each iteration. The other pointer, the "Hare" moves forward two nodes each iteration. If there's no loop, the hare and tortoise will both reach the end of the list. If there is a loop, the Hare will pass the Tortoise at some point and when that happens, you know there's a loop. This is O(1) space complexity and a pretty simple algorithm.
Use the algorithm to reverse a linked list. If the list has a loop, you'll end up back at the beginning of the list while trying to reverse it. If it doesn't have a loop, you'll finish reversing it and hit the end. This is O(1) space complexity, but a slightly uglier algorithm.
I you count your Nodes and get to the *head again.
How about following approach:
Sort the link list in ascending order by following any standard algorithms.
Before sort: 4-2-6-1-5
After Sort: 1-2-4-5-6
Once sorted, check for each node data and compare with link node's data, something like this:
if(currentcode->data > currentnode->link->data)
i.e. circular = true;
At any comparison, if any of "currentnode->data" is greater than "currentcode->link->data" for a sorted link list, it means current node is pointed to some previous node(i.e circular);
Guys, i dont have setup to test the code.Let me now if this concept works.
Use the Tortoise-Hare algorithm.
A algorithm is:
Store the pointer to the first node
Traverse through the list comparing each node pointer to this pointer
If you encounter a NULL pointer, then its not circularly linked list
If you encounter the first node while traversing then its a circularly linked list
#samoz has in my point of view the answer! Pseudo code missing. Would be something like
yourlist is your linked list
allnodes = hashmap
while yourlist.hasNext()
node = yourlist.next()
if(allnodes.contains(node))
syso "loop found"
break;
hashmap.add(node)
sorry, code is very pseudo (do more scripting then java lately)
Start at one node and record it, then iterate through the entire list until you reach a null pointer or the node you started with.
Something like:
Node start = list->head;
Node temp = start->next;
bool circular = false;
while(temp != null && temp != start)
{
if(temp == start)
{
circular = true;
break;
}
temp = temp->next;
}
return circular
This is O(n), which is pretty much the best that you will able to get with a singly linked list (correct me if I'm wrong).
Or to find any cycles in the list (such as the middle), you could do:
Node[] array; // Use a vector or ArrayList to support dynamic insertions
Node temp = list->head;
bool circular = false;
while(temp != null)
{
if(array.contains(temp) == true)
{
circular = true;
break;
}
array.insert(temp);
temp = temp->next;
}
return circular
This will be a little bit slower due to the insertion times of dynamic arrays.
Here is a nice site on which the different solutions can copied.
find loop singly linked list
This is the winner on that site
// Best solution
function boolean hasLoop(Node startNode){
Node slowNode = Node fastNode1 = Node fastNode2 = startNode;
while (slowNode && fastNode1 = fastNode2.next() && fastNode2 = fastNode1.next()){
if (slowNode == fastNode1 || slowNode == fastNode2) return true;
slowNode = slowNode.next();
}
return false;
}
This solution is "Floyd's
Cycle-Finding Algorithm" as published
in "Non-deterministic Algorithms" by
Robert W. Floyd in 1967. It is also
called "The Tortoise and the Hare
Algorithm".
It will never terminate from the loop, it can also be done in following solution:
bool hasCircle(List l)
{
Iterator i = l.begin(), j = l.begin();
while (true) {
// increment the iterators, if either is at the end, you're done, no circle
if (i.hasNext()) i = i.next(); else return false;
// second iterator is travelling twice as fast as first
if (j.hasNext()) j = j.next(); else return false;
if (j.hasNext()) j = j.next(); else return false;
// this should be whatever test shows that the two
// iterators are pointing at the same place
if (i.getObject() == j.getObject()) {
return true;
}
if(i.next()==j)
break;
}
}
Try this
/* Link list Node */
struct Node
{
int data;
struct Node* next;
};
/* This function returns true if given linked
list is circular, else false. */
bool isCircular(struct Node *head)
{
// An empty linked list is circular
if (head == NULL)
return true;
// Next of head
struct Node *node = head->next;
// This loop would stope in both cases (1) If
// Circular (2) Not circular
while (node != NULL && node != head)
node = node->next;
// If loop stopped because of circular
// condition
return (node == head);
}

Categories

Resources