-1

Finding a cycle in singly linked list and find the node from where cycle starts. I have seen use of two pointers( generally slow and fast) to find the cycle but I have written this code and it seems to be working fine. My question is, is there something my code is missing out on, while finding the cycle in singly linked list.

Node* find_cycle_node(Node *head){
Node *p=head;
     Node *q;
     while(p->next!=null)
    { 
              q=p->next;
        while(q->next!=null)
          { 
                     if(p==q) return q; //Node repeated i.e cycle
                     else (q=q->next;)
           }
                p=p->next;
      }
    return null; // no cycle detected
}
  • with `return;`, you'll get compiling error. `return NULL`, if no cycle detected – Deidrei Dec 26 '13 at 02:21
  • 1
    This site's not for code reviews. If there's no specific problem with your code that you don't understand, then you should ask for general feedback elsewhere. – Tony Delroy Dec 26 '13 at 02:22
  • Well, I guess one thing you may want to consider is not only correctness but also runtime. Your algorithm looks like it runs in O(n^2), whereas the two-pointer one (tortoise and hare) runs in something like O(n) time, I believe. – J Trana Dec 26 '13 at 02:33
  • @J Trana: I also think along the similar lines. But, If I observe it closely, its not exactly O(n^2). For every iteration of outer loop, my inner loop decreases by one node. I am not running inner loop 'n' times in every iteration. Its probably less than O(n^2). – user2773985 Dec 26 '13 at 02:39
  • if O(n) space complexity is accepted, there can be O(n) time complexity algorithm – Krypton Dec 26 '13 at 02:54
  • http://en.wikipedia.org/wiki/Cycle_detection describes some common algorithms to solve that. – Jarod42 Dec 26 '13 at 20:53

6 Answers6

5

Your inner loop will not terminate if there is cycle which is a couple nodes down the handle, e.g., it will be an infinite loop for something like this:

1 -> 2 -> 3 -> 4 -> 5
          ^         |
          |         |
          +---------+
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • I am sorry, but I did not get this point. When, pointer p come at node 3, pointer q will be set to node 4 and then node 5 and finally node 3. Now, my condition will be true (p==q) now it will return node q ( i.e. 3 ) and program will terminate. – user2773985 Dec 26 '13 at 02:34
  • @user2773985: in the first outer iteration `p` is at node 1. `q` gets initialized with node 2, moves to node 3 and keeps going through the sequence 4, 5, 3 infinitely. It will never reach a node where the next pointer is null nor will it ever become equal to `p`. – Dietmar Kühl Dec 26 '13 at 02:36
  • Oh, there you go! I was not able to find this error. Great Catch. – user2773985 Dec 26 '13 at 02:42
1

How about this ?

struct Node_
{
    int ix ;
    struct Node_* next ;
} ;
typedef struct Node_ NODE ;
NODE *head = NULL ;

int main()
{
    NODE* n1 ;
    n1 = (NODE*) malloc(sizeof(NODE)) ;
    n1->ix = 0 ;
    n1->next = NULL ;
    head = n1 ;
    NODE* n2 ;
    n2 = (NODE*) malloc(sizeof(NODE)) ;
    n2->ix = 1 ;
    n2->next = NULL ;
    n1->next = n2 ;
    NODE* n3 ;
    n3 = (NODE*) malloc(sizeof(NODE)) ;
    n3->ix = 2 ;
    n3->next = NULL ;
    n2->next = n3 ;
    NODE* n4 ;
    n4 = (NODE*) malloc(sizeof(NODE)) ;
    n4->ix = 3 ;
    n4->next = n2 ;
    n3->next = n4 ;

    unordered_map<NODE*,int> hashx ;
    int idx ;
    NODE* p = head ;
    while(p != NULL)
    {
        hashx[p] += 1 ;
        if(hashx[p] >= 2)
        {
            printf("node p (%d) recycle !!\n",p->ix);
            break ;
        }
        p = p->next ;
    }
    printf("done \n") ;
} //main
barfatchen
  • 1,630
  • 2
  • 24
  • 48
0

is there something my code is missing out on

return; // no cycle detected

This line looks pretty bad, it should be changed to s.th. like

return NULL; // no cycle detected
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
0

To me your inner loop condition appears to be ambiguous. You are analysing if (p==q) where q is p-> next. this means that the node p previously considered didn't haD A CYCLE. So to me your inner loop wil never terminate.

you must consider this:-

#include <iostream>
using namespace std;
class Node{
    public:
        int data;
        Node * next;
        Node(int x){
            data = x;
            next = NULL;
        }
        Node(int x, Node * y){
            data = x; 
            next = y;
        }
};
class linkedList{
    Node *head;
    public:
        linkedList(){
            head = NULL;
        }
        void addNode(int value){
            Node *p;
            if(head == NULL)
                head = new Node (value, NULL);
            else{
                p = head;
                while(p->next !=NULL)
                    p=p->next;
                    p->next = new Node (value, NULL);
            }
        }
        void print(){
            Node * p;
            p = head;
            while(p != NULL){
                cout << p->data;
                p = p->next;
            }
        }
        int findCycle(){
            Node *p, *start, *q;
            p = head;
            while(p != NULL){
                q = p->next;
                while (q != NULL ){
                    if(p->data == q->data)
                         return q->data;
                    else
                         q = q->next;
                }
                p = p->next;
            }
            return 0;
        }
};
int main(){
    linkedList l1;
    l1.addNode(1);
    l1.addNode(2);
    l1.addNode(3);
    l1.addNode(4);
    l1.addNode(5);
    l1.addNode(3);
    int node = l1.findCycle();
    cout<<node;
    return 0;
}

What do you say people about this code.

o12d10
  • 800
  • 3
  • 17
  • 31
  • Your version also may have infinite loop. – Jarod42 Dec 26 '13 at 03:16
  • @Jarod42 I have updated the code. Currently this one is not going in an infinite loop.. . . But my question here is that the one who asked a the question is referring to same data at different location as a loop - "Question is from Cracking the Coding Interview." My code is answer to same data . and for it to be a cycle referring to same node we just have to change the if condition to 'if(p == q)' this checks for the memory location. if the memory reference is same then there will be a cycle – o12d10 Dec 26 '13 at 19:34
  • @yashgard1232: OP wants to detect cycle for ill formed list. He doesn't want to find duplicated values. So you misunderstood the question. – Jarod42 Dec 26 '13 at 20:44
0
void LinkListOps::createCycledListAndFindACycleNode()

{ // build a list with a cycle in it

ZNODE* head = new ZNODE(0);
ZNODE* current = head;
ZNODE* cycle = 0;

for (int i = 1; i < 8; i++)
{
    current->_next = new ZNODE(i);
    current = current->_next;

    if (i == 6)
        cycle = current;

    if (i == 7)
        current->_next = cycle;
}

// verify that there is a cycle
ZNODE* slow = head;
ZNODE* fast = head;
ZNODE* cycleNode = 0;

while (slow && fast && fast->_next)
{
    slow = slow->_next;
    fast = fast->_next->_next;

    if (slow == fast)
    {
        cycleNode = slow;
        break;
    }

}

if (cycleNode == 0)
{
    printf("No cycle\n");
    return;
}

// finally find a cycle node which will be p2
ZNODE* p1 = head;
ZNODE* p2 = cycleNode;

while (1)
{
    for (p2 = cycleNode; p2->_next != cycleNode; p2 = p2->_next)
    {
        if (p2 == p1)
            break;          
    }

    if (p2 == p1)
        break;

    p1 = p1->_next;
}

printf("%d\n", p2->_i);

}

Ezra
  • 49
  • 4
0

You can quickly find out if there is a loop in a linked list by doing the following:

ptr = head;
current = nullptr;
if (!ptr) {
  current = ptr->next;
  while(current && current!=ptr) {
    current = current->next;
    if (current) {
      current = current->next;
    }
    ptr = ptr->next;
  }
}

At the end of this, if current is not null, then a loop was found, and current will be somewhere inside of it. This works by iterating current twice as fast through the list as ptr, and will always find a loop, if any exists, before ptr has looped once.

markt1964
  • 2,638
  • 2
  • 22
  • 54