Java - Ordered Linked List algorithm - java

I have a problem in understanding the algorithm of the Linked List, if someone could explain for me, I understood almost everything only a specific part, when the new added item is less than the previous item so we have to move the new item to the left
public boolean addItem(ListItem newItem) {
if (this.root == null) {
// The list was empty, so this item becomes the head of the list
this.root = newItem;
return true;
}
ListItem currentItem = this.root;
while (currentItem != null) {
int comparison = (currentItem.compareTo(newItem));
if (comparison < 0) {
// newItem is greater, move right if possible
if (currentItem.next() != null) {
currentItem = currentItem.next();
} else {
// there is no next, so insert at end of list
currentItem.setNext(newItem).setPrevious(currentItem);
return true;
}
} else if (comparison > 0) {
// newItem is less, insert before
if (currentItem.previous() != null) {
currentItem.previous().setNext(newItem);//previous entry is now the added item
newItem.setPrevious(currentItem.previous()); //the new item previous entry is setted to the current item previous value
newItem.setNext(currentItem); //pointing the new item to the current item
currentItem.setPrevious(newItem); //the previous entry of the current item is equal with the new item
} else {
// the node with a previous is the root
newItem.setNext(this.root).setPrevious(newItem);
this.root = newItem;
}
return true;
} else {
// equal
System.out.println(newItem.getValue() + " is already present, not added.");
return false;
}
}
return false;
}
so where comparison is greater than 0, so lets say I have: 9 11 10 in my Linked List, so the previous entry of 10, which is 11 goes to the previous position to the right, newItem(10)is setted to the previous position with the currentItem.previous value, so the current item is not also 10 now ?

The algorithm is simple. To make it clearer, let me replace the code blocks with a simple English explanation of what it does:
if the list is empty, put the new item as the root of the list.
otherwise, if the list has items, take the root as the current item to compare it to.
this will go over a few iterations until we find the right spot to insert the new item.
For every iteration:
if the new item is bigger than the current spot on the list, move up one spot in the
list to compare next time.
else, if the new item is smaller than the current spot,
and the current spot is not the root of the list - insert
the new item between the current spot and the one before it.
If the current spot is the root of the list, make the new item
the root of the list and tag along the entire list as its next items.
And that's it - you always get a sorted list after a few iterations (the most iterations is the length of the list). you start from the beginning of the list and look at each item against the one you have to insert. If as long as it's bigger than the current spot you move up the list. When you passed the spot it needs to be (the previous spot was smaller, the next spot is bigger) you just insert it in the middle. And you may insert it at the very beginning or at the very end. I hope that helps you understand the algorithm better.

This is implementation of
sorted Linked List
No duplicates are allowed in Linked List
All elements are unique and in ascending order.

Related

Java Linked List pointer confusion

This Code below is from a java LinkedList implementation.The method adds a string element at an index point of the list and is taken from one of my cs books.
The linked list class has 2 global private variables
Node first;
Node last;
public void add(int index, String e) {
if (index < 0 || index > size()) {
String message = String.valueOf(index);
throw new IndexOutOfBoundsException(message);
}
// Index is at least 0
if (index == 0) {
// New element goes at beginning
first = new Node(e, first);
System.out.println("ran");
if (last == null)
last = first;
return;
}
// Set a reference pred to point to the node that
// will be the predecessor of the new node
Node pred = first;
for (int k = 1; k <= index - 1; k++) {
pred = pred.next;
}
// Splice in a node containing the new element
pred.next = new Node(e, pred.next);
System.out.println(toString());
// Is there a new last element ?
if (pred.next.next == null)
System.out.println("ran");
last = pred.next;
}
My question
I don't understand how Node first, last get updated in the condition below
Suppose you have a list that looks like ["1","2","3","7","4","5,"6"]
Then you add the the element "4" to index 3
So, the list looks likes ["1","2","3","4","7","4","5,"6"], but looking at the code of the add method I don't know how the first or last node pointers gets updated. Because in my mind these are the only pieces of code that run because the index isn't 0 and the last doesn't change
EDIT
The Object Node first is used in the toString method(not shown) to traverse through the collection
// Set a reference pred to point to the node that
// will be the predecessor of the new node
Node pred = first;
for (int k = 1; k <= index - 1; k++) {
pred = pred.next;
}
// Splice in a node containing the new element
pred.next = new Node(e, pred.next);
System.out.println(toString());
Before the add, the first element is "1" and the last element is "6".
After the add, the first element is "1" and the last element is "6".
You're right that the first and last dont change-- they don't need to, because you haven't changed the first or the last element.
I think you are getting bogged down by the way this linked list implementation works. The first and last pointers exist to just keep track of the start and end of the list. Hence, when you insert an element in the middle of the list, these pointers do not get updated, nor is there any need for such an update. But they do get updated should an insert land before the current head or after the current tail of the list. Here is the code which handles head inserts:
if (index == 0) {
// New element goes at beginning
first = new Node(e, first);
System.out.println("ran");
if (last == null)
last = first;
return;
}
The critical line here is actually this:
first = new Node(e, first);
The first pointer gets assigned to a new node, which in turn points to the old first node. Similarly, should an insert of a new node land at the end of the list, the following code will handle that:
if (pred.next.next == null) {
System.out.println("ran");
last = pred.next;
}
Here the last pointer is assigned to the new node which was inserted after the old last.
But other than these two edge cases, there is no need to update first and last with inserts.
If the index is 0, the node is added in the beginnng and the for loop doesn’t work.
If it is 1, the loop again doesn’t execute and node is simply added to the list.
However if it something else, then until the index-1 position is reached the loop shifts each element one step behind. Then the code just outside the loop (which slices in a node containing new element) inserts the element at index.
If after the loop has executed, the index turns out to be the last one then the last node is updated.
Hope this helps!

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)

deleting a specific item from a java LL

So I'm trying to delete an item from a linked list in java.I'm not using java's predefined LL but I'm working with my own.
I know the concept to delete an item is to traverse in the link and compare the data in the list one by one.
so here's what I came up with, but it doesn't work!
public void delStudent(int regN) {
Node current = head;
Node q = head;
if (current.getStudent().getRegN() == regN) {
head = head.link;
}
for (int i = 0; i < this.length() - 1; i++) {
if (current.getStudent().getRegN() != regN) {
current = current.link;
q = current;
}
}
q.link= current.link.link;
}
Well, if your list is empty, the execution of the if statement in the beginning will immediately give a NullPointerException (because current will be null). Generally, for the LinkedList delete method, you must consider three cases: size == 0, size == 1, and size > 1 (where size is the number of nodes in the Linked List).
public void delStudent(int regN) {
Node current = head;
Node previous = head;
while (current != null ){ // keep traversing till end of list
if (current.getStudent().getRegN() == regN) { // found it!
previous.link = current.link; // relink
if (current == head){ // edge case : removed first element
head = current.link; // move head forward.
}
break;
} else {
previous = current;
current = current.link;
}
}
}
The above code assumes regN is unique and that there is only one student with that regN. Hope this helps.
The mistake is (I think) in these three lines:
current = current.link;
q = current;
(where you set q to be the same as current) and
q.link= current.link.link;
(and maybe also in using length() depending on it's implementation)
To see why let's look at how to delete in more detail:
Let's consider there are three nodes in your list x->y->z and you want to delete y.
In order to do so you need to set x.link = z.
To return to you example it means that the variable q should store the element before current, then deleting current can be done by
q.link = current.link;
In order order to have q be the predecessor of current you have to reverse the two lines above, i.e., use
q = current;
current = current.link;
Why am I saying depending on the implementation of length ? If you implementation of length just returns some number maintained by increasing whenever you add a value to the list, you should also decrement it when deleting one. If length traverses the list in order to find the number of elements then its ok, although not very efficient.
One last comment: your code will not work (even with the fixes I explain above) when there is no element with the given regN. Why? Because you always delete one element. Moreover, you might want to rethink the logic inside the loop. Currently if the element to delete is the second one and there is 1000000 elements you will run the loop nearly 1000000 times.
When you are checking each node you need to delete the node or break once you find a match. You need to maintain a node for the previous node to be able to delete the current node once you find a match.
I just realized that you were attempting to to that with Node q
for (int i = 0; i < this.length() - 1; i++) {
if (current.getStudent().getRegN() != regN) {
q = current;
current = current.link;
} else{ //we have a match
//remove the link to the current item
q.link = current.link;
break;
}
if you are using a doubly linked list you can use node.prev().link = current.link;

Need to remove duplicate nodes in linked list

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;
}
}
}

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