Splitting Linklist in two parts - c

Given a list, split it into two sublists — one for the front half, and one for the back half. If the number of elements is odd, the extra element should go in the front list. So FrontBackSplit() on the list {2, 3, 5, 7, 11} should yield the two lists {2, 3, 5} and {7, 11}.
code is this.
void FrontBackSplit(Node *head, Node **front, Node **back) {
if (!head) return; // Handle empty list
Node *front_last_node;
Node *slow = head;
Node *fast = head;
while (fast) {
front_last_node = slow;
slow = slow->next;
fast = (fast->next) ? fast->next->next : NULL;
}
front_last_node->next = NULL; // ends the front sublist
*front = head;
*back = slow;
}
Problem is I am not getting best run-time and sometimes expected output.

Generally, your code works well for even-sized lists. Consider a list of 4 elements A -> B -> C -> D -> NULL and take a look at your algorithm trace.
A slow, fast, head
B
C
D
NULL
A front_last_node, head
B slow
C fast
D
NULL
A head
B front_last_node
C slow
D
NULL fast
Then you erase the link B->C and return two lists: A -> B and C -> D. This is exactly the wanted behavior of this function, isn't it?

There is another way ;
Use a loop to calculate how many elements are in the linked list.
If its couple - the first list is between head(the address of the first element) to i=n/2 element. The second list is between i=0.5n+1 element to the last one.
Else the first list is between the head to the i=0.5n+1 element and the second is between i=0.5n+2 to the last one.
To make it easy, when you run the loop to calculate the number of elements, use a variable to keep the place of the last one and the middle one, so it will be easy to use them when needed.

Related

Deduplication optimization

The problem is as follows. I want a function that, given a list and a max number of occurrences "x", deletes all elements of the list that appear more than x times or x times.
I found a pretty straightforward solution, which is to check for each of the elements. This said, to repeat the find and delete functions many times seems computationally-wise not optimal to me.
I was wondering whether you could provide a better algorithm (i excluded allocating memory for a matrix from the min to the max... just too much for the task... say you have few very big numbers and your memory won't do it.)
My code follows.
typedef struct n_s
{
int val;
struct n_s *next;
}
n_t;
// deletes all elements equal to del in list with head h
n_t * delete(n_t *h, int del);
// returns the first occurrence of find in list with head h, otherwise gives NULL
n_t * find(n_t *h, int find);
n_t *
delFromList(n_t *h, int x)
{
int val;
n_t *el, *posInter;
// empty list case
if (h == NULL)
return NULL;
// first element
val=h->val;
if ( (posInter = find(h -> next,val))
&& (find(posInter -> next, val)))
h = delete(h, val);
// loop from second element
el = h;
while (el -> next)
{
val = el -> next -> val;
// check whether you want to delete the next one,
// and then if you do so, check again on the "new" next one
if ((posInter = find(el -> next -> next, val))
&& (find(posInter -> next, val)))
el -> next = delete(el -> next, val);
// in case you did not delete the nexy node, you can move on
else
el = el -> next;
}
return h;
}
I know that the el->next->next may look confusing, but I find it less intuitive to use variables such as "next", "past"... so, sorry for your headache.
One option for an algorithm with improved performance is:
Define a data structure D with two members, one for the value of a list element and one to count the number of times it appears.
Initialize an empty balanced tree ordered by value.
Iterate through the list. For each item in the list, look it up in the tree. If it is not present, insert a D structure into that tree with its value member copied from the list element and its count set to one. If it is present in the tree, increments its count. If its count equals or exceeds the threshold, remove it from the list.
Lookups and insertions in a balanced tree are O(log n). A linked list of n items uses n of them, and deletions from a linked list are O(1). So the total time is O(n log n).
Use a counting map to count the number of times each element appears. The keys are the elements, and the values are the counts.
Then, go through your array a second time, deleting anything which meets your threshold.
O(n) time, O(n) extra space.

Sorting an array using subscripts without moving array elements

I have to sort an array of non-negative ints using mergesort in C, but there's a catch - I cant move around the actual array elements, like if I have {3,5,6,7,0,4,1,2}, the desired output should be
First element is at subscript: 4
0 3 5
1 5 2
2 6 3
3 7 -1
4 0 6
5 4 1
6 1 7
7 2 0
See how the ordering of the original input stays the same but only the keys get swapped as the numbers are compared? So far, my main functions are:
void Merge(int *A,int *L,int leftCount,int *R,int rightCount)
{
int i,j,k;
// i - to mark the index of left sub-array (L)
// j - to mark the index of right sub-array (R)
// k - to mark the index of merged sub-array (A)
i = 0; j = 0; k =0;
while(i<leftCount && j< rightCount)
{
if(L[i] <= R[j])
{
//something important;
i++;
}
else
{
//something important;
j++;
}
}
i=0;
j=0;
while(i < leftCount) A[k++] = L[i++]; //merge all input sequences without swapping initial order
while(j < rightCount) A[k++] = R[j++];
}
// Recursive function to sort an array of integers.
void MergeSort(int *A,int n)
{
int mid,i,k, *L, *R;
if(n < 2)
{
return;
}
mid = n/2; // find the mid index.
// create left and right subarrays
// mid elements (from index 0 till mid-1) should be part of left sub-array
// and (n-mid) elements (from mid to n-1) will be part of right sub-array
L = (int*)malloc(mid*sizeof(int));
R = (int*)malloc((n- mid)*sizeof(int));
for(i = 0;i<mid;i++) L[i] = A[i]; // creating left subarray
for(i = mid;i<n;i++) R[i-mid] = A[i]; // creating right subarray
MergeSort(L,mid); // sorting the left subarray
MergeSort(R,n-mid); // sorting the right subarray
Merge(A,L,mid,R,n-mid); // Merging L and R into A as sorted list.
free(L);
free(R);
}
I know that I have to initialize the index of all the elements as -1 at the bottom of the recursion tree when there are only single elements during the merge-sort. And then I have to change those indices accordingly as I compare array elements from Left array vs Right array. But thats where Im stuck. My professor told the class to use a linked list - but Im having a tough time visualizing HOW i can implement a linked list to achieve this indexing thing. I dont want my homework to be done by someone else, I just want someone to explain in pseudocode how I should go about it, and then I can write the actual code myself. But Im so lost, Im sorry if the question is poorly asked, but Im brand spanking new here and Im freaking out :(
Ok. lets start with a simple example, a list of 4 elements to sort, lets go through the process of what your function needs to do and how it does it in terms of linked lists:
#->[3]->[1]->[4]->[2]->$
Ok, so here # is your pointer to the first element, in this case [3], which has a pointer to the second, and so on. I shall use ->$ as a null pointer (not pointing to anything) and ->* as a 'I don't care' pointer (where a pointer may exist, but want to show a conceptional break in the list)
We now perform multiple passes to merge these into one sorted list.
This is the first pass, so we treat it as if we have multiple lists of length 1:
#->* [3]->* [1]->* [4]->* [2]->*
In reality, these remain linked for now, but this is the conceptional model.
so what to we need 'know' at this time?
the end of the list before list #1
reference to beginning of list #1
reference to beginning of list #2
reference to item after list #2
Then we merge the two sublists (2) and (3) onto the end of (1), by taking the minimum of the heads of the lists, detaching that, and ammending it to (1), moving onto the next value in that list if it exists
conceptional
//sublists length 1. we'll work on the first pair
#->* [3]->* [1]->* [4]->* [2]->*
//smallest element from sublists added to new sublist
#->* [3]->* [4]->* [2]->* //
[1]->*
//above repeated until sublists are both exhausted
#->* [4]->* [2]->*
[1]->[3]->*
//we now have a sorted sublist
#->* [1]->[3]->* [4]->* [2]->*
actual
//(1-4) are pointers to the list as per description above
#->[3]->[1]->[4]->[2]->$
| | | |
1 2 3 4
//set the end of the lists (2) and (3) to point to null, so
//when we reach this we know we have reached the end of the
//sublist (integrity remains because of pointers (1-4)
#->* [3]->$ [1]->$ [4]->[2]->$
| | | |
1 2 3 4
//the smallest (not null) of (2) and (3) is referenced by (1),
//update both pointers (1) and (2) or (3) to point to the next
//item
#->[1]->* [3]->$ $ [4]->[2]->$
| | | |
1 2 3 4
//repeat until both (2) and (3) point to null
#->[1]->[3]->* $ $ [4]->[2]->$
| | | |
1 2 3 4
We now have a linked list with the first sublist in it. Now, we keep track of (1), and move on to the second pair of sublists, starting with (4), repeating the process.
Once (2),(3) and (4) are all null, we have completed the pass. We now have sorted sublists, and a single linked list again:
#->[1]->[3]->[2]->[4]->$ $ $ $
| | | |
1 2 3 4
Now we do the same, only with sublists twice the length. (and repeat)
The list is sorted when sublist length >= length of linked list.
At no point during this have we actually moved any data around, only modified the links between the items in the linked list.
This should give you a solid idea of what you need to do from here.
I've extended this to some actual code:
See it here
I wrote it in python, so it satisfies your desire for pseudocode, as it isn't code for the language that you are writing in.
pertinent function with additional comments:
def mergesort(unsorted):
#dummy start node, python doesn't have pointers, but we can use the reference in here in the same way
start = llist(None)
start.append(unsorted)
list_length = unsorted.length()
sublist_length = 1
#when there are no sublists left, we are sorted
while sublist_length < list_length:
last = start
sub_a = start.next
#while there are unsorted sublists left to merge
while sub_a:
#these cuts produce our sublists (sub_a and sub_b) of the correct length
#end is the unsorted content
sub_b = sub_a.cut(sublist_length)
end = sub_b.cut(sublist_length) if sub_b else None
#I've written this so is there are any values to merge, there will be at least one in sub_a
#This means I only need to check sub_a
while sub_a:
#sort the sublists based on the value of their first item
sub_a, sub_b = sub_a.order(sub_b)
#cut off the smallest value to add to the 'sorted' linked list
node = sub_a
sub_a = sub_a.cut(1)
last = last.append(node)
#because we cut the first item out of sub_a, it might be empty, so swap the references if so
#this ensures that sub_a is populated if we want to continue
if not sub_a:
sub_a, sub_b = sub_b, None
#set up the next iteration, pointing at the unsorted sublists remaining
sub_a = end
#double the siblist size for the next pass
sublist_length *=2
return start.next
Create a linked list of items whereby each list item has both the value and index of each array item. So aside from prev/next, each item in the linked list is a struct that has struct members uint value; and uint index; .
Pre-populate the link-list just by iterating the array and for each array element, append a new linked-list item to the list and set the value and index of the array element in each linked-list item as they are added to the list.
Use the pre-populated linked-list as a "proxy" for the actual array values and sort the linked list as if it were the original array. I.e. instead of sorting based on myArray[i], sort based on currentLinkListItem.value .
As speaking of linked lists:
typedef struct ValueNode
{
struct ValueNode* next;
int* value;
} ValueNode;
typedef struct ListNode
{
struct ListNode* next;
ValueNode* value;
} ListNode;
Singly linked lists are sufficient...
Now first the merge algorithm:
ValueNode* merge(ValueNode* x, ValueNode* y)
{
// just assuming both are != NULL...
ValueNode dummy;
ValueNode* xy = &dummy;
while(x && y)
{
ValueNode** min = *x->value < *y->value ? &x : &y;
xy->next = *min;
*min = (*min)->next;
xy = xy->next;
}
// just append the rest of the lists - if any...
if(x)
{
xy->next = x;
}
else if(y)
{
xy->next = y;
}
return dummy.next;
}
The dummy is just for not having to check the for NULL within the loop...
Now let's use it:
int array[] = { 3, 5, 6, 7, 0, 4, 1, 2 };
ListNode head;
ListNode* tmp = &head;
for(unsigned int i = 0; i < sizeof(array)/sizeof(*array); ++i)
{
// skipping the normally obligatory tests for result being 0...
ValueNode* node = (ValueNode*) malloc(sizeof(ValueNode));
node->value = array + i;
node->next = NULL;
tmp->next = (ListNode*) malloc(sizeof(ListNode));
tmp = tmp->next;
tmp->value = node;
}
tmp->next = NULL;
Now we have set up a list of lists, each containing one single element. Now we merge pairwise two subsequent lists. We need to pay attention: If we merge two lists into one, keep it as the new head and merge the next one into it, and so on, then we would have implemented selection sort! So we need to make sure that we do not touch an already merged array before all others are merged. That is why the next step looks a little complicated...
while(head.next->next) // more than one single list element?
{
tmp = head.next;
while(tmp)
{
ListNode* next = tmp->next;
if(next)
{
// we keep the merged list in the current node:
tmp->value = merge(tmp->value, next->value);
// and remove the subsequent node from it:
tmp->next = next->next;
free(next);
}
// this is the important step:
// tmp contains an already merged list
// -> we need to go on with the NEXT pair!
tmp = tmp->next;
// additionally, if we have an odd number of lists,
// thus at the end no next any more, we set tmp to NULL,
// too, so we will leave the loop in both cases...
}
}
Finally, we could print the result; note that we only have one single linked list left within your outer linked list:
ValueNode* temp = head.next->value;
while(temp)
{
printf("%d\n", *temp->value);
temp = temp->next;
}
What is yet missing is freeing the allocated memory - I'll leave that to you...

How to traverse through n elements in a doubly linked list in C?

As the title suggests, I have to iterate through a doubly linked list. The only problem is that I have to iterate through "n" elements.
For example, if I'm given a list of, 1 3 2 2 1 1, I have to iterate left or right depending on the value I'm on so:
1 -> 3 -> 1 -> 1. I can move over the same value as the value in the list. Since I start at 1, I can move left or right 1 element (can only go right). When I land on 3 I can move left or right 3 elements etc.
while (temp->next != NULL) {
//traverse n elements left or right
}
If I always just had to traverse 1 elements at a time it's as easy as
temp = temp->next;
If someone could explain a strategy to traversing 'n' elements depending on the value of the node, that would be much appreciated.
edit: You can only go in the direction if there are enough elements in that direction. So in the case of 1 -> 3, you can only go 3 to the right after.
I think your question is to traverse through n elements, where n is the value of the current node.
The code would be like ~
int tr;
while (temp->next != NULL)
{
tr=temp->data; // temp->data holds the value of the current node.
Node *leftptr = temp, *rightptr = temp;
while(tr!=0 && rightptr!=NULL) //moves right side
{
rightptr = rightptr->next;
tr--;
}
tr=temp->data;
while(tr!=0 && leftptr!=NULL) //moves left side
{
leftptr = leftptr->prev;
tr--;
}
}
You can implement your algorithm and choose how to traverse, given both the traversal rules.

Finding the junction node in a linklist having a loop in it [duplicate]

How can I detect that whether a singly linked-list has loop or not??
If it has loop then how to find the point of origination of the loop i.e. the node from which the loop has started.
You can detect it by simply running two pointers through the list, this process is known as the tortoise and hare algorithm after the fable of the same name:
First off, check if the list is empty (head is null). If so, no cycle exists, so stop now.
Otherwise, start the first pointer tortoise on the first node head, and the second pointer hare on the second node head.next.
Then loop continuously until hare is null (which may be already true in a one-element list), advancing tortoise by one and hare by two in each iteration. The hare is guaranteed to reach the end first (if there is an end) since it started ahead and runs faster.
If there is no end (i.e., if there is a cycle), they will eventually point to the same node and you can stop, knowing you have found a node somewhere within the cycle.
Consider the following loop which starts at 3:
head -> 1 -> 2 -> 3 -> 4 -> 5
^ |
| V
8 <- 7 <- 6
Starting tortoise at 1 and hare at 2, they take on the following values:
(tortoise,hare) = (1,2) (2,4) (3,6) (4,8) (5,4) (6,6)
Because they become equal at (6,6), and since hare should always be beyond tortoise in a non-looping list, it means you've discovered a cycle.
The pseudo-code will go something like this:
def hasLoop (head):
return false if head = null # Empty list has no loop.
tortoise = head # tortoise initially first element.
hare = tortoise.next # Set hare to second element.
while hare != null: # Go until hare reaches end.
return false if hare.next = null # Check enough left for hare move.
hare = hare.next.next # Move hare forward two.
tortoise = tortoise.next # Move tortoise forward one.
return true if hare = tortoise # Same means loop found.
endwhile
return false # Loop exit means no loop.
enddef
The time complexity for this algorithm is O(n) since the number of nodes visited (by tortoise and hare) is proportional to the number of nodes.
Once you know a node within the loop, there's also an O(n) guaranteed method to find the start of the loop.
Let's return to the original position after you've found an element somewhere in the loop but you're not sure where the start of the loop is.
head -> 1 -> 2 -> 3 -> 4 -> 5
^ |
| V
8 <- 7 <- 6
\
x (where hare and tortoise met).
This is the process to follow:
Advance hare and set size to 1.
Then, as long as hare and tortoise are different, continue to advance hare, increasing size each time. This eventually gives the size of the cycle, six in this case.
At this point, if size is 1, that means you must already be at the start of the cycle (in a cycle of size one, there is only one possible node that can be in the cycle so it must be the first one). In this case, you simply return hare as the start, and skip the rest of the steps below.
Otherwise, set both hare and tortoise to the first element of the list and advance hare exactly size times (to the 7 in this case). This gives two pointers that are different by exactly the size of the cycle.
Then, as long as hare and tortoise are different, advance them both together (with the hare running at a more sedate pace, the same speed as the tortoise - I guess it's tired from its first run). Since they will remain exactly size elements apart from each other at all times, tortoise will reach the start of the cycle at exactly the same time as hare returns to the start of the cycle.
You can see that with the following walkthrough:
size tortoise hare comment
---- -------- ---- -------
6 1 1 initial state
7 advance hare by six
2 8 1/7 different, so advance both together
3 3 2/8 different, so advance both together
3/3 same, so exit loop
Hence 3 is the start point of the cycle and, since both those operations (the cycle detection and cycle start discovery) are O(n) and performed sequentially, the whole thing taken together is also O(n).
If you want a more formal proof that this works, you can examine the following resources:
a question on our sister site;
the Wikipedia cycle detection page; or
"The Tortoise and the Hare Algorithm" by Peter Gammie, April 17, 2016.
If you're simply after support for the method (not formal proof), you can run the following Python 3 program which evaluates its workability for a large number of sizes (how many elements in the cycle) and lead-ins (elements before the cycle start).
You'll find it always finds a point where the two pointers meet:
def nextp(p, ld, sz):
if p == ld + sz:
return ld
return p + 1
for size in range(1,1001):
for lead in range(1001):
p1 = 0
p2 = 0
while True:
p1 = nextp(p1, lead, size)
p2 = nextp(nextp(p2, lead, size), lead, size)
if p1 == p2:
print("sz = %d, ld = %d, found = %d" % (size, lead, p1))
break
The selected answer gives an O(n*n) solution to find the start node of the cycle. Here's an O(n) solution:
Once we find the slow A and fast B meet in the cycle, make one of them still and the other continue to go one step each time, to decide the perimeter of the cycle, say, P.
Then we put a node at the head and let it go P steps, and put another node at the head. We advance these two nodes both one step each time, when they first meet, it's the start point of the cycle.
You can use hash map also to finding whether a link list have loop or not below function uses hash map to find out whether link list have loop or not
static bool isListHaveALoopUsingHashMap(Link *headLink) {
map<Link*, int> tempMap;
Link * temp;
temp = headLink;
while (temp->next != NULL) {
if (tempMap.find(temp) == tempMap.end()) {
tempMap[temp] = 1;
} else {
return 0;
}
temp = temp->next;
}
return 1;
}
Two pointer method is best approach because time complexity is O(n) Hash Map required addition O(n) space complexity.
I read this answer in Data structure book by Narasimha Karamanchi.
We can use Floyd cycle finding algorithm, also known as tortoise and hare algorithm. In this, two pointers are used; one (say slowPtr) is advanced by a single node, and another (say fastPtr) is advanced by two nodes. If any loop is present in the single linked list, they both will surely meet at some point.
struct Node{
int data;
struct Node *next;
}
// program to find the begin of the loop
int detectLoopandFindBegin(struct Node *head){
struct Node *slowPtr = head, *fastPtr = head;
int loopExists = 0;
// this while loop will find if there exists a loop or not.
while(slowPtr && fastPtr && fastPtr->next){
slowPtr = slowPtr->next;
fastPtr = fastPtr->next->next;
if(slowPtr == fastPtr)
loopExists = 1;
break;
}
If there exists any loop then we point one of the pointers to the head and now advance both of them by single node. The node at which they will meet will be the start node of the loop in the single linked list.
if(loopExists){
slowPtr = head;
while(slowPtr != fastPtr){
fastPtr = fastPtr->next;
slowPtr = slowPtr->next;
}
return slowPtr;
}
return NULL;
}
For the most part all the previous answers are correct but here is a simplified version of the logic with visual & code (for Python 3.7)
The logic is very simple as others explained it. I'm gonna create Tortoise/slow and Hare/fast. If we move two pointers with different speed then eventually fast will meet the slow !! you can also think of this as two runners in a tack circular field. If the fast runner keeps going in circle then it will meet/pass the slow runner.
So, we will move Tortoise/slow pointer with speed 1 for each iteration while we keep incrementing or move the Hare/fast pointer with speed of 2. Once they meet we know there is a cycle. This is also known as Floyd's cycle-finding algorithm
Here is the Python code that does this (notice has_cycle method is the main part):
#!/usr/bin/env python3
class Node:
def __init__(self, data = None):
self.data = data
self.next = None
def strnode (self):
print(self.data)
class LinkedList:
def __init__(self):
self.numnodes = 0
self.head = None
def insertLast(self, data):
newnode = Node(data)
newnode.next = None
if self.head == None:
self.head = newnode
return
lnode = self.head
while lnode.next != None :
lnode = lnode.next
lnode.next = newnode # new node is now the last node
self.numnodes += 1
def has_cycle(self):
slow, fast = self.head ,self.head
while fast != None:
if fast.next != None:
fast = fast.next.next
else:
return False
slow = slow.next
if slow == fast:
print("--slow",slow.data, "fast",fast.data)
return True
return False
linkedList = LinkedList()
linkedList.insertLast("1")
linkedList.insertLast("2")
linkedList.insertLast("3")
# Create a loop for testing
linkedList.head.next.next.next = linkedList.head;
#let's check and see !
print(linkedList.has_cycle())
Following code will find whether there is a loop in SLL and if there, will return then starting node.
int find_loop(Node *head){
Node * slow = head;
Node * fast = head;
Node * ptr1;
Node * ptr2;
int k =1, loop_found =0, i;
if(!head) return -1;
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;
}
}
if(loop_found){
/* We have detected a loop */
/*Let's count the number of nodes in this loop node */
ptr1 = fast;
while(ptr1 && ptr1->next != slow){
ptr1 = ptr1->next;
k++;
}
/* Now move the other pointer by K nodes */
ptr2 = head;
ptr1 = head;
for(i=0; i<k; i++){
ptr2 = ptr2->next;
}
/* Now if we move ptr1 and ptr2 with same speed they will meet at start of loop */
while(ptr1 != ptr2){
ptr1 = ptr1->next;
ptr2 = ptr2->next;
}
return ptr1->data;
}
boolean hasLoop(Node *head)
{
Node *current = head;
Node *check = null;
int firstPtr = 0;
int secondPtr = 2;
do {
if (check == current) return true;
if (firstPtr >= secondPtr){
check = current;
firstPtr = 0;
secondPtr= 2*secondPtr;
}
firstPtr ++;
} while (current = current->next());
return false;
}
Another O(n) solution.
As I viewed the selected answer, I tried a couple of examples and found that:
If (A1,B1), (A2,B2) ... (AN, BN) are the traversals of pointers A and B
where A steps 1 element and B steps 2 elements, and, Ai and Bj are the nodes traversed by A and B, and AN=BN.
Then, the node from where the loop starts is Ak, where k = floor(N/2).
ok - I ran into this in an interview yesterday - no reference material available and I came up with a very different answer (while driving home of course...) Since the linked lists are NORMALLY (not always I admit) allocated using malloc logic then we know that the granularity of the allocations is known. On most systems this is 8 bytes - this means that the bottom 3 bits are always zeros. Consider - if we place the linked list in a class to control access and use a mask of 0x0E ored into the next address then we can use the lower 3 bits to store a break crumb Thus we can write a method that will store our last breadcrumb - say 1 or 2 - and alternate them. Our method that checks for a loop can then step through each node (using our next method) and check if the next address contains the current breadcrumb - if it does we have a loop - if it does not then we would mask the lower 3 bits and add our current breadcrumb. The breadcrumb checking algorithm would have to be single threaded as you could not run two of them at once but it would allow other threads to access the list async - with the usual caveats about adding/deleting nodes.
What do you think? If others feel this is a valid solution I can write up the sample class ... Just think sometimes a fresh approach is good and am always willing to be told I have just missed the point... Thanks All Mark
Another solution
Detecting a Loop:
create a list
loop through the linkedlist and keep on adding the node to the list.
If the Node is already present in the List, we have a loop.
Removal of loop:
In the Step#2 above, while loop through the linked list we are also keep track of the previous node.
Once we detect the loop in Step#3, set previous node's next value to NULL
#code
def detect_remove_loop(head)
cur_node = head
node_list = []
while cur_node.next is not None:
prev_node = cur_node
cur_node = cur_node.next
if cur_node not in node_list:
node_list.append(cur_node)
else:
print('Loop Detected')
prev_node.next = None
return
print('No Loop detected')
Firstly, Create a Node
struct Node {
int data;
struct Node* next;
};
Initialize head pointer globally
Struct Node* head = NULL;
Insert some data in Linked List
void insert(int newdata){
Node* newNode = new Node();
newNode->data = newdata;
newNode->next = head;
head = newNode;
}
Create a function detectLoop()
void detectLoop(){
if (head == NULL || head->next == NULL){
cout<< "\nNo Lopp Found in Linked List";
}
else{
Node* slow = head;
Node* fast = head->next;
while((fast && fast->next) && fast != NULL){
if(fast == slow){
cout<<"Loop Found";
break;
}
fast = fast->next->next;
slow = slow->next;
}
if(fast->next == NULL){
cout<<"Not Found";
}
}
}
Call the function from main()
int main()
{
insert(4);
insert(3);
insert(2);
insert(1);
//Created a Loop for Testing, Comment the next line to check the unloop linkedlist
head->next->next->next->next = head->next;
detectLoop();
//If you uncomment the display function and make a loop in linked list and then run the code you will find infinite loop
//display();
}
bool FindLoop(struct node *head)
{
struct node *current1,*current2;
current1=head;
current2=head;
while(current1!=NULL && current2!= NULL && current2->next!= NULL)
{
current1=current1->next;
current2=current2->next->next;
if(current1==current2)
{
return true;
}
}
return false;
}
A quite different method:-
Reverse the linked list.
While reversing if you reach the head again then there is a loop in the list,
if you get NULL then there is no loop.
The total time complexity is O(n)

merged linked list in C

This question was asked to me in an interview:
There are two header of two linked lists.
There is a merged linked list in c where in the second linked list is merged into the first one at some point.
How could we identify the merging point and what is the complexity of finding that point ?
Could anybody please help?
O(n)
search = list1->header;
if (mixed->header == list1->header) search = list2->header;
while (mixed->next != search) mixed = mixed->next;
Edit: new name for variables and a few comments
/* search is what we want to find. Here it's the head of `list2` */
search = list2->header;
/* unless the merging put `list2` first; then we want to search for `list1` */
if (mixed->header == list2->header) search = list1->header;
/* assume (wrongly) that the header for the mixed list is the merge point */
mergepoint = mixed->head;
/* traverse the mixed list until we find the pointer we're searching */
while (mergepoint->next != search) mergepoint = mergepoint->next;
/* mergepoint now points to the merge point */
Update: This assumes the Y-shaped joining of two linked lists as described better in Steve Jessop's post. But I think the description of the problem is sufficiently ambiguous that various interpretations are possible, of which this is only one.
This can be done with a single pass through one list plus a partial pass through the other. In other words, it's O(n).
Here's my proposed algorithm:
Create a hashmap. (Yes, this is busywork in C if you don't have a library handy for it).
The keys will be pointers to the items in List1 (i.e. the head pointer and each link).
The values will be integers denoting the position, i.e. distance from the head of List1.
Run through List1, keeping track of the position, and hash all your pointers and positions.
Run through List2, keeping track of the position, and find the first pointer that occurs in the hashmap.
At this point, you'll know the position in List2 of the first node common to both lists.
The hashmap entry will also contain the position in List1 of that same node.
That will nicely identify your merge point.
Do you mean you have a Y-shape, like this:
list1: A -> B -> C -> D -> E -> F
list2: X -> Y -> Z -> E -> F
Where A .. Z are singly-linked list nodes. We want to find the "merge point" E, which is defined to be the first node appearing in both lists. Is that correct?
If so, then I would attach the last node of list2 (F) to the first node of list2 (X). This turns list2 into a loop:
list2 : X -> Y -> Z -> E -> F -> X -> ...
But more importantly:
list1 : A -> B -> C -> D -> E -> F -> X -> Y -> Z -> E -> ...
This reduces the question to a previously-solved problem, which can be solved in O(n) time and O(1) additional storage.
But reading your question, another possibility is that by "merge" you mean "insert". So you have two lists like this:
list1: A -> B -> C
list2: D -> E -> F
and then another completely separate list:
list3: A -> B -> D -> E -> F -> C
where this time, A .. F are the values contained in the list, not the nodes themselves.
If the values are all different, you just need to search list3 for D (or for the later of D and A, if you don't know which list it was that was copied into the other). Which seems like a pointless question. If values can be repeated, then you have to check for the full sequence of list2 inside list3. But just because you find "DEF" doesn't mean that's where list2 was inserted - maybe "DEF" already occurred several times in list1 beforehand, and you've just found the first of those. For instance if I insert "DEF" into "ABCDEF", and the result is "ABCDEFDEF", then did I insert at index 3 or at index 6? There's no way to tell, so the question can't be answered.
So, in conclusion, I don't understand the question. But I might have answered it anyway.
If the question means list2 contained in list1 (that is list2 points somewhere in the middle of list1), then it is easy - just walk list1 and compare pointers until you reach list2.
However such interpretation does not make much sense, because by inserting list2 into the list1 (like 1 1 2 2 1), you would also modify list2 - the last 1 becomes part of list2.
So I will assume the question is about the Y shape:
list1: A -> B -> C -> D -> E -> F
list2: X -> Y -> Z -> E -> F
This can be solved using hashtable as Carl suggested.
Solution without a hashtable would be this:
Walk list1 and disconnect all its pointers as you go
Walk list2. When it ends, you've reached the junction point
Repair the pointers in list1
Disconnecting and repairing pointers in list1 can be done easily using recursion:
Diconnect(node)
{
if (node->next == NULL)
walk list2 to its end, that is the solution, remember it
else
{
tmp = node->next;
node->next = NULL;
Disconnect(tmp);
node->next = tmp; // repair
}
}
Now call Disconnect(list1).
That is recurse down list1 and disconnect pointers. When you reach end, execute step 2 (walk list2 to find junction), repair pointers when returning back from recursion.
This solution modifies list1 temporarily, so it is not thread safe and you should use a lock around the Disconnect(list1) call.
//try this code for merge
void mergeNode(){
node *copy,*current,*current1;
free(copy);
merge=NULL;
current=head;
current1=head1;
while(current!=NULL){
if(merge==NULL){
node *tmp;
tmp=(node*)malloc(sizeof(node));
tmp->data=current->data;
tmp->link=NULL;
merge=tmp;
}
else{
copy=merge;
while(copy->link!=NULL)
copy=copy->link;
node *tmp;
tmp=(node*)malloc(sizeof(node));
tmp->data=current->data;
tmp->link=copy->link;
copy->link=tmp;
}
current=current->link;
}
while(current1!=NULL){
copy=merge;
while(copy->link!=NULL)
copy=copy->link;
node *tmp;
tmp=(node*)malloc(sizeof(node));
tmp->data=current1->data;
tmp->link=copy->link;
copy->link=tmp;
current1=current1->link;
}
display(merge);
}
Sorry if my answer seems too simple, but if you have two linked list which are identified by a header and you join them, so that
A -> B -> C -> D is the first list, and
1 -> 2 -> 3 -> 4 is the second, then suppose
A -> B -> C -> 1 -> 2 -> 3 -> 4 -> D is the result
then to find the merging point you need to go through the final list until you find the second header (the 1). Which goes in O(n1) worst case, where n1 is the number of elements of the first list (this happens if the second list is merged at the end).
That's how I would intend the question. The reference to the C language would probably mean that you have no 'object' or pre-packaged data structure, unless specified.
[update] as suggested by Sebastian, if the two list above have the same elements my solution won't work. I suspect that this is where the C language comes into action: you can search for the address of the first element of the second list (the head). Thus the duplicates objection won't hold.
Well, there are several approaches to solve this problem.
Note that i am only discussing the approaches[corner cases may need to be handled separately] starting from brute force to the best one.
Considering N: number of nodes in first linked list
M: number of nodes in second linked list
Approach 1:
Compare each node of first linked list with every other node of second list. Stop when you find a matching node, this is the merging point.
while(head1)
{
cur2=head2;
while(cur2)
{
if(cur2==head1)
return cur2;
cur2=cur2->next;
}
head1=head1->next;
}
Time Complexity: O(N*M)
Space Complexity: O(1)
Approach 2:
Maintain two stacks. Push all the nodes of he first linked list to first stack. Repeat he same for second linked list.
Start popping nodes from both the stacks until both popped nodes do not match. The last matching node is the merging point.
Time Complexity: O(N+M)
Space Complexity: O(N+M)
Approach 3:
Make use of hash table. Insert all the nodes of the first linked list into hash.
Search for the first matching node of he second list in the hash.
This is the merging point.
Time Complexity: O(N+M)
Space Complexity: O(N)
Note that the space complexity may vary depending upon the hash function used[talking about C where you are supposed to implement your own hash function].
Approach 4:
Insert all the nodes of first linked list[by nodes, i mean addresses] into an array.
Sort the array with some stable sorting algorithm in O(N logN) time[Merge sort would be better].
Now search for the first matching node from the second linked list.
Time Complexity: O(N logN)
Space Complexity: O(N)
Note that this approach may be better than Approach 3 [in terms of space]as it doesn't use a hash.
Approach 5:
1. Take an array of size M+N.
2. Insert each node from the first linked list, followed by inserting each node from the second linked list.
3. Search for the first repeating element[can be found in one scan in O(M+N) time].
Time Complexity: O(N+M)
Space Complexity: O(N+M)
Approach 6: [A better approach]
1. Modify the first linked list & make it circular.
2. Now starting from the head of the second linked list, find the start of the loop using Floyd- Warshall cycle detection algorithm.
3. Remove the loop[can be easily removed as we know the last node].
Time Complexity: O(N+M)
Space Complexity: O(1)
Approach 7: [Probably the best one]
1. Count the number of nodes in first linked list[say c1].
2. Count the number of nodes in second linked list[say c2].
3. Find the difference[Lets say c1>c2] diff=c1-c2.
4. Take two pointers p1 & p2, p1 pointing to the head of the first linked list & p2 pointing to the head of the second linked list.
5. Move p1 diff times.
6. Move both p1 & p2 each node at a time until both point to the same node.
7. p1 or p2 indicates the merging point.
Time Complexity: O(N+M)
Space Complexity: O(1)
Trivial solution is obviously O(N+M). Hm.. What could be better. You can go from start to end of the list or vice versa. When you have a threads, you can go these directions at the some time, so should be a litter bit quicker.

Resources