I am able to understand the basic principle on how Floyd's cycle-finding algorithm works. Only thing I am not able to understand is the while loop condition which is as below:
while(slow && fast && fast->next){
slow = slow->next;
/*Moving fast pointer two steps at a time */
fast = fast->next->next;
if(slow == fast){
loop_found = 1;
break;
}
}
Since fast->next will move fastest and will become NULL in the first place. Why can't we just put fast->next in while the loop. While doing so will I be missing on some boundary conditions?
while(fast->next) instead of `while(slow && fast && fast->next)`
I wrote below code and it worked fine for both even and odd ordered linear linked list. So, Do we need the fastPtr condition in the while loop just for the empty linked list check. Please enlighten.
void linklist::detect()
{
node * fastPtr = new node;
node * slwPtr = new node;
slwPtr = head;
fastPtr = head;
while (/*slwPtr!=NULL && fastPtr!=NULL &&*/ fastPtr->next!=NULL)
{
fastPtr = fastPtr->next->next;
slwPtr = slwPtr->next;
if (fastPtr == slwPtr)
{
cout << "Loop Detected\n";
break;
}
}
}
Consider an empty linked list where slow and fast is null, we require the null checks in place. We can avoid the slow null check because of what you cited.
while(fast && fast->next) //This should do.
Considering your solution, we will end up in Segmentation Fault because of dereferencing Null Pointers.
The while check is added to check if the node is not NULL as in these scenarios:
Empty Linked list. fast = NULL.
Linear Linked List i.e with no loops (2 nodes).
Consider a linked list 1->2->NULL
First iteration: fast = 1 and gets modified as fast =NULL
Second iteration: Segmentation fault for while(fast->next)
Related
I wrote a program to merge two sorted linked list into one and this function was the one I used to do it but it's not working. The code of the function is as follows is as follows:
void combine(Node **temp, Node *temp_1, Node *temp_2){
while(temp_1 != NULL || temp_2 != NULL){
if(temp_1->data > temp_2->data){
push(temp, temp_2->data);
temp_2 = temp_2->next;
}
else{
push(temp, temp_1->data);
temp_1 = temp_1->next;
}
}
while(temp_1 != NULL){
push(temp, temp_1->data);
temp_1 = temp_1->next;
}
while(temp_2 != NULL){
push(temp, temp_2->data);
temp_2 = temp_2->next;
}
}
Now, this code doesn't add anything to the final linked list. If I write something like
push(temp, temp_1->data);
it will add elements just fine so the problem isn't definitely with the push function. Can someone tell me what is the problem with the above code?
The full code is in the following URL:
https://ide.geeksforgeeks.org/FZ8IS4PADE
The issue is the while condition:
while(temp_1 != NULL || temp_2 != NULL){
This will allow the execution of the body of the loop when just one of those two pointers is null, and this will result in undefined behaviour on the first statement in that body:
if(temp_1->data > temp_2->data){
The || should be an &&. This will fix your issue.
Other remarks on your code
Don't use NULL for comparing your pointer variables against, but nullptr
The use of push makes your code inefficient: at every push, your code is starting an iteration through the whole list to find the end of it. Since you actually know what is the last node (since it was created in the previous iteration of the loop) this is a waste of time. Instead, keep a reference to the tail of the list that is being created. As there is no tail at the start of the combine process, it might be useful to create a "sentinel" node that comes before the real list that will be returned.
Use better variable names. temp is not temporary at all. It is the result that the caller wants to get: this name is misleading.
Avoid code repetition. The last two loops are the same except for the list that is copied from, and this code is again similar to the parts in the main loop. So create a function that does this job of copying a node from a source list to the end of another list, and that advances both pointers.
Here is what that would look like:
void copyNode(Node **source, Node **targetTail) {
*targetTail = (*targetTail)->next = new Node((*source)->data);
*source = (*source)->next;
}
void combine(Node **result, Node *head_1, Node *head_2){
Node *sentinel = new Node(0); // Dummy
Node *current = sentinel;
while(head_1 != nullptr && head_2 != nullptr){
if(head_1->data > head_2->data){
copyNode(&head_2, ¤t);
}
else{
copyNode(&head_1, ¤t);
}
}
if (head_1 == nullptr) {
head_1 = head_2;
}
while (head_1 != NULL) {
copyNode(&head_1, ¤t);
}
*result = sentinel->next;
delete sentinel;
}
So I have two linked lists, each holding a color:
1.black->2.black->3.black->4.black->5.black->NULL
1.red ->2.red ->3.red ->4.red ->5.red ->NULL
I want the function to return
1.black->2.red ->3.black->4.red ->5.black->NULL
1.red ->2.black->3.red ->4.black->5.red ->NULL.
Lets name the first pointers, firstBlack and firstRed. To achieve this "checkerboard" pattern, I switch the nodes that each first is pointing to with a simple swap to the other list, advance the pointer two spots, then repeat until I'm at the end of the list.
while(firstBlack->next != NULL && firstRed->next != NULL) {
Node * temp = firstBlack->next;
firstBlack->next = firstRed->next;
firstRed->next = temp;
firstBlack = firstBlack->next->next;
firstRed = firstRed->next->next;
}
However, the function isn't doing what it's supposed to although I'm fairly certain that my logic is correct. I am also getting seg faults :(
This is a simple enough code, please use a debugger and debug the code step by step.
Also please post the entire code not just what's in the while loop.
This code should work correctly.
//Some methods to create these linked lists.
pBlackHead = CreateBlackList();
pRedHead = CreateRedList();
firstBlack = pBlackHead;
firstRed = pRedHead;
while(firstBlack->next != NULL && firstRed->next != NULL){
Node * temp = firstBlack->next;
firstBlack->next = firstRed->next;
firstRed->next = temp;
firstBlack = firstBlack->next;
firstRed = firstRed->next;}
While printing the list to check the correctness use pBlackHead , pRedHead. A debugger is not currently available on the system I am using but this should work.
You are advancing two steps without checking end conditions. Because you have an odd number of items, you dereference a null pointer.
You don't need to care which tail originated in which list to swap them
for(; left->next && right->next; left = left->next, right = right->next) {
std::swap(left->next, right->next);
}
I'm working on this find merge node method on hackerrank. My approach is: while both of the nodes are not null, I want to move one of the list to their next node, that's what flag variable is for. But somehow it's giving me segmentation fault? Did I accidentally access a null variable? Someone please enlighten me. Below is my method code.
Constraint: Both lists will converge and both lists are non-NULL
int FindMergeNode(Node *headA, Node *headB)
{
// Complete this function
// Do not write the main method.
bool flag = true;
while(headA != headB){
if(flag) headA=headA->next;
else headB=headB->next;
flag = !flag;
}
return headA->data; //or headB->data;
}
You make two assumptions:
1. There exists such node.
2. The distance of this node from the beginning of each list differs by at most 1 between the two lists. You alternately move forward in one list and then check to see if you got to the same node (by address). so if list1 has no nodes before the one you are looking for, and list2 has 2 nodes before it, you won't find a match.
If I understand your question correctly, the truth is that the distance from the end of the list is the same (because their tails are the same).
Why to use flag directly use the condition to check if it is the last node
if(headA->next ==NULL)
headA=headA->next;
else if (headB->next== NULL )
headB=headB->next;
Complete solution would be something
int FindMergeNode(Node *headA, Node *headB) {
Node *currentA = headA;
Node *currentB = headB;
//Do till the two nodes are the same
while(currentA != currentB){
//If you reached the end of one list start at the beginning of the other one
//currentA
if(currentA->next == NULL){
currentA = headB;
}else{
currentA = currentA->next;
}
//currentB
if(currentB->next == NULL){
currentB = headA;
}else{
currentB = currentB->next;
}
}
return currentB->data;
}
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);
}
I'm trying to find this algorithm on C++ in .NET but can't, I found this one:
// 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;
}
but doesn't seem to be right, or am I wrong? How can I actually prove that my hare will meet tortoise at the end? Thanks in advance for any explanation how exactly does it work and proof
EDITED
About this solution, I found that in regular algorithm they use only one fast iterator but here they use two, why?
The idea in the code you've found seems fine. Two fast iterators are used for convenience (although I'm positive such kind of 'convenience', like putting a lot of 'action' in the condition of while loop, should be avoided). You can rewrite it in more readable way with one variable:
while (fastNode && fastNode.next()) {
if (fastNode.next() == slowNode || fastNode.next().next() == slowNode) {
return true;
}
fastNode = fastNode.next().next();
slowNode = slowNode.next();
}
The algorithm is correct. Proof:
The case of no cycle is trivial: the hare will find the end of the list.
So, there's a cycle, and the hare enters it, running around like crazy. Eventually, the tortoise reaches the first node of the cycle. From this point on, both necessarily stay in the cycle: the only way they can go from a node is to the next node, which eventually leads back to the first node of the cycle. (Draw a picture of the list/graph to convince yourself.)
Since the hare moves faster, it will eventually catch up with the tortoise. Depending on the length of the cycle and the number of nodes traversed before entering it (whether they are odd or even is what matters, so there are four cases), this may happen after an odd or an even number of steps. That's why the hare should check both its current node and the next node for the tortoise's presence. (The example code uses two pointers to achieve this, though that's not really necessary.)
For a more formal proof, check out this Wikipedia page.
This algorithm will find a cycle in a linked list.
one fast node can be used instead:
function boolean hasLoop(Node startNode){
Node slowNode = Node fastNode = startNode;
while (slowNode && fastNode = fastNode.next() && fastNode = fastNode.next()){
if (slowNode == fastNode) return true;
slowNode = slowNode.next();
}
return false;
}