22from abc import ABCMeta , abstractmethod
33
44from datastructures .linked_lists .exceptions import EmptyLinkedList
5+ from datastructures .linked_lists .linked_list_utils import (
6+ has_cycle ,
7+ detect_node_with_cycle ,
8+ cycle_length ,
9+ remove_cycle ,
10+ )
511
612T = TypeVar ("T" )
713
@@ -379,14 +385,7 @@ def has_cycle(self):
379385 :return: True if there is a cycle, False otherwise
380386 :rtype: bool
381387 """
382- fast_pointer = slow_pointer = self .head
383- while fast_pointer and slow_pointer and fast_pointer .next :
384- fast_pointer = fast_pointer .next .next
385- slow_pointer = slow_pointer .next
386-
387- if slow_pointer == fast_pointer :
388- return True
389- return False
388+ return has_cycle (self .head )
390389
391390 def cycle_length (self ) -> int :
392391 """
@@ -395,105 +394,25 @@ def cycle_length(self) -> int:
395394 Returns:
396395 int: length of the cycle or number of nodes in the cycle
397396 """
398- if not self .head :
399- return 0
400- slow_pointer = fast_pointer = self .head
401-
402- while fast_pointer and fast_pointer .next :
403- slow_pointer = slow_pointer .next
404- fast_pointer = fast_pointer .next .next
405-
406- # Cycle detected
407- if slow_pointer is fast_pointer :
408- length = 1
409- # Move slow pointer by one step to start counting
410- slow_pointer = slow_pointer .next
411-
412- # Continue moving the slow pointer until it meets the fast pointer again
413- while slow_pointer != fast_pointer :
414- length += 1
415- slow_pointer = slow_pointer .next
416-
417- return length
418-
419- return 0
397+ return cycle_length (self .head )
420398
421399 def detect_node_with_cycle (self ) -> Optional [Node ]:
422400 """
423401 Detects the node with a cycle and returns it
424402 """
425- if not self .has_cycle ():
426- return None
427- else :
428- slow_pointer = fast_pointer = self .head
429-
430- while fast_pointer and slow_pointer and fast_pointer .next :
431- fast_pointer = fast_pointer .next .next
432- slow_pointer = slow_pointer .next
433-
434- if slow_pointer == fast_pointer :
435- break
436- else :
437- return None
438-
439- while self .head != slow_pointer :
440- slow_pointer = slow_pointer .next
441- self .head = self .head .next
442- return self .head
403+ return detect_node_with_cycle (self .head )
443404
444- def remove_cycle (self ):
405+ def remove_cycle (self ) -> Optional [ Node ] :
445406 """
446407 Removes cycle if there exists. This will use the same concept as has_cycle method to check if there is a loop
447408 and remove the cycle
448- if one is found.
449- 1) Detect Loop using Floyd’s Cycle detection algo and get the pointer to a loop node.
450- 2) Count the number of nodes in loop. Let the count be k.
451- 3) Fix one pointer to the head and another to kth node from head.
452- 4) Move both pointers at the same pace, they will meet at loop starting node.
453- 5) Get pointer to the last node of loop and make next of it as NULL.
454- :return: True if the cycle has been removed, False otherwise
455- :rtype: bool
409+ Returns:
410+ Node: head node with cycle removed
456411 """
457- fast_pointer = slow_pointer = self .head
458-
459- while fast_pointer and slow_pointer and fast_pointer .next :
460- fast_pointer = fast_pointer .next .next
461- slow_pointer = slow_pointer .next
462-
463- if slow_pointer == fast_pointer :
464- pointer_1 = pointer_2 = slow_pointer
465-
466- # Count the number of nodes in loop
467- k = 1
468- while pointer_1 .next != pointer_2 :
469- pointer_1 = pointer_1 .next
470- k += 1
471-
472- # Fix one pointer to head
473- pointer_1 = self .head
474-
475- # And the other pointer to k nodes after head
476- pointer_2 = self .head
477- for _ in range (k ):
478- pointer_2 = pointer_2 .next
479-
480- # Move both pointers at the same place
481- # they will meet at loop starting node
482- while pointer_2 != pointer_1 :
483- pointer_1 = pointer_1 .next
484- pointer_2 = pointer_2 .next
485-
486- # Get pointer to the last node
487- pointer_2 = pointer_2 .next
488- while pointer_2 .next != pointer_1 :
489- pointer_2 = pointer_2 .next
490-
491- # Set the next node of the loop ending node
492- # to fix the loop
493- pointer_2 .next = None
494- return True
412+ if not self .head or not self .head .next :
413+ return self .head
495414
496- return False
415+ return remove_cycle ( self . head )
497416
498417 @abstractmethod
499418 def alternate_split (self ):
0 commit comments