Understanding linked list sorting - c

I am having trouble understanding how this bit of code sorts a linked list.
node* sort(node *head) {
struct node* point;
struct node* small;
struct node* stay;
int temp;
stay = head;
while (stay != NULL) {
point = stay->next;
small = stay;
while (point != NULL) {
if (point->data < small->data) {
small = point;
}
point = point->next;
}
temp = stay->data;
stay->data = small->data;
small->data = temp;
stay = stay->next;
}
return head;
}
I have tried to follow it along on paper and my thought process leads me to believe that if we were to run this function, a list would be sorted like this:
5 -> 2 -> 1 -> 3
2 -> 5 -> 1 -> 3
2 -> 1 -> 5 -> 3
2 -> 1 -> 3 -> 5
My understanding is that the first while loop traverses the list each time until it reaches the last node, while the second while loop compares the two nodes point and small. If the data needs to be switched, the next block of code actually does the switching, and then stay moves on to the next node in the list, with point being the node after that. How does the code know to go back to the very first node and keep comparing, so that 2 gets switched with 1? Thank you for your help.

This piece of code implements selection sort: Starting from stay (small == stay), it searches for the least value following and as soon as found (i. e. end of list reached) swaps.
Be aware that in case of stay being smallest, it is swapped with itself (you could prevent this with an appropriate test before: if(small != stay) { /* swap */ }.
So actually, your sorting steps are as follows:5 -> 2 -> 1 -> 3
1 -> 2 -> 5 -> 3
1 -> 2 -> 5 -> 3 (second node swapped with itself)
1 -> 2 -> 3 -> 5
1 -> 2 -> 3 -> 5 (fourth node swapped with itself)
Actually, there is one step more, as the last node always is swapped with itself (while(stay != NULL) stops only after last node).
First node is treated correctly right from the start (in the first run of the outer loop) as stay is initially set to head.

Related

In a perfectly balanced binary tree convert from preorder to inorder

So I have a perfectly balanced (Each node has two children, if it doesn't have any children, it is a leaf node) binary search tree
1
2 9
3 6 10 11
4 5 7 8 12 13 14 15
and I have that in an array in pre-order
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
now how do I convert my array to in-order or post order ?
well, somehow yesterday I misunderstood your question, or you didn't explain it well. anyway, the thing is that --
you have an array which contains the nodes of a tree, placed in
preorder traversal by the tree; now you want to 'reverse-engineer' of
it such that you can build or make a tree again from that array so that you can traverse IN or POST order, whatever you required to do!
now one thing you need to understand when you are making the array from the tree, your array should contain the nodes which have value, as well as the nodes which don't have. in another way, you have to place the null nodes of the tree inside of the array, such that you can differentiate the nodes which have value and the nodes which don't have!! pretty simple!
so, what you need to do is, while traversing the tree, you should follow this two-step--
if node has value, put it in array
else put -1 in array [-1 denotes null value]
now, after traversing the tree and make the array from that tree, you can decode the array to construct back the tree from the array.
PROCEDURE TO MAKE ARRAY FROM TREE
DO LEVEL ORDER TRAVERSAL
IF ROOT HAS A VALUE, PUT IT IN ARRAY
ELSE, PUT -1 IN ARRAY
REPEAT, UNTIL ALL NODES, BEEN TRAVERSED
PSEUDOCODE
FUNCTION encode(TREE root, Array a){
Queue q;
q->add(root);
i = 0;
a[i++] = root->node;
while(!q){
TREE temp = q->front();
q->pop();
/* if temp's left node contains value */
if(temp->left){
a[i++] = temp->left->node;
q->push(temp->left);
}else{
/* if temp's left node doesn't contains value */
a[i++] = -1;
}
/* do the same for right sub-tree */
if(temp->right){
a[i++] = temp->right->node;
q->push(temp->right);
}else{
/* if temp's left node doesn't contains value */
a[i++] = -1;
}
}
return a;
}
now you can reverse the algorithm to construct a tree from the array, and after that you can do POST or IN whatever you need!
PROCEDURE TO MAKE TREE FROM ARRAY
CREATE ROOT
1.1 PUT ROOT IN A QUEUE
TRAVERSE I-TH INDEX FROM ARRAY
2.1 IF ARRAY[INDEX] != -1 , CREATE NODE ON LEFT
2.2 ELSE PUT NULL ON LEFT
TRAVERSE I+1-TH INDEX FROM ARRAY
3.1 IF ARRAY[INDEX] != -1 , CREATE NODE ON RIGHT
3.2 ELSE PUT NULL ON RIGHT
CONTINUE UNTIL QUEUE BECOMES EMPTY
PSEUDOCODE
FUNCTION decode(Array a){
/* creating root */
TREE root;
IF (a[0] == -1)
root = createNode(a[0]);
ELSE
root = NULL;
Queue q;
q->push(root);
i = 0;
while(!q){
TREE temp = q.front();
q->pop();
/* if array's index contain value, create node */
if(a[i+1] != -1){
temp->left = createNode(a[i+1]);
q->push(temp->left);
}else{
/* else assing null */
temp->left = NULL;
}
/* do the same for right subtree */
if(a[i+2] != -1){
temp->right = createNode(a[i+2]);
q->push(temp->right);
}else{
/* else assing null */
temp->right= NULL;
}
i += 2;
}
}
Now you could able to make a tree from the array you have! and can traverse the tree to get IN or POST order traversal!!
HAPPY FRIDAY : )
Is this homework? "In/Pre/Post-Order" is a description of how the tree is to be traversed, not how it is structured.
First of all, you should know the difference between BT and BST. Binary Tree states it has two children, or one child, or doesn't have a child at all;
Where Binary Search Tree, is special Binary Tree, that has smaller value in the left part and higher value in right. This property is following each and every property/node of BST.
Now, you have a binary tree, you want to traverse the tree in - IN, PRE and POST order. And consider this is the traversing way, not the structure
of the tree.
**Rules of PRE-ORDER:**
1. Visit -> Root
2. Process -> Left Child
3. Process -> Right Child
4. Continue (until Root is Empty)
** Rules of IN-ORDER: **
1. Process -> Left Child
2. Visit -> Root
3. Process -> Right Child
4. Continue (until Root is Empty)
** Rules of POST-ORDER: **
1. Process -> Left Child
2. Process -> Right Child
3. Visit -> Root
4. Continue (until Root is Empty)
I am assuming, you already traversed in PRE-ORDER.
** IN-ORDER Traversal of your TREE **
4 -> 3 -> 5 -> 2 -> 7 -> 6 -> 8 -> 1 -> 12 -> 10 -> 13 -> 9 -> 14 -> 11 -> 15
** POST-ORDER Traversal of your TREE **
4 -> 5 -> 3 -> 7 -> 8 -> 6 -> 2 -> 12 -> 13 -> 10 -> 14 -> 15 -> 11 -> 9 -> 1
EDIT: Visit here to understanding the traversing -> https://medium.com/quick-code/data-structures-traversing-trees-9473f6d9f4ef

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.

Linked List loop

What exactly does this code fragment do?
#include <stdio.h>
List *makeList(int n) {
List *l, *l1 = NULL;
for (int i = 0; i < n; i++) {
l = malloc(sizeof(List));
l->val = n-i;
l->next = l1;
l1 = l;
}
return l;
}
My notes say that "Given a number n,
build a list of length n where
the ith element of the list
contains i"
But I don't get that...
The tricky thing here is that the list is built backwards, note that each element's value is set to n - i, and i counts from 0 to n - 1. So, the first element will get value n, the next one will get n - 1, and so on.
This is probably done in order to save on a variable (!); otherwise it would be required to have another pointer to remember the first node, in order to have something to return.
Also, it doesn't check the return value of malloc(), which is always scary.
For n = 0, it will return an undefined value (the value of l), which is really scary.
It creates a linked list of n nodes and returns the head of list. The values are : 1,2,3,...n (from head to tail).
It looks like this:
1 -> 2 -> 3 -> ...... -> n -> (NULL)
Does it help?
This is creating list in reverse order. In other words at the beginning last element of list is being created and its value is list size (n) - 0 (i) which is list element number.
It does something like this; each box is one malloc:
n n-1 n-2 1
^ ^ ^ ^
+--|---+ +--|---+ +--|---+ +--|---+
| val | | val | | val | ... | val |
NULL <-- next | <-- next | <-- next | <-- next |
+------+ +------+ +------+ +------+
^^--- this is returned
The data structure struct List looks like this (more or less):
struct List
{
int val;
struct List * next;
};
Its name is misleading, as it should really be "ListNode" or something like that. There is usually no dedicated "list" data structure in C, just a collection of nodes. You simply pass around the head node and treat that as "the list".
(A dedicated holder structure for the entire list might be useful if you want to store the list size to access it in constant time, or if you have a doubly-linked list and want to have both head and tail pointer available in constant time.)
Let's trace your code.
List *l, *l1 = NULL;
defines two pointer variables of type List.
for (int i = 0; i < n; i++) {
you are starting a loop, which will traverse n times. Which means, if you call this function with 5, this loop will execute 5 times.
l = malloc(sizeof(List));
creates a List value in the memory, and stores the location of that value in the l pointer variable. For every pass through the loop, a different List value is created in the memory.
l->val = n-i;
assigns a value n-i to the val field of the newly created List value. For the first pass through the loop, i will be 0, so the val will contain 5 - 0, which is 5. For the second pass, i is 1, so for the second List, the val will contain 5 - 1, which is 4, and so on.
l->next = l1;
there is a next field in the List type, which is a pointer of the same type. For the first pass, li contains NULL, so it will point to null. For the second pass, l1 will contain the previously created List value, so the second List's next field will point it to that, and so on.
l1 = l;
stores the memory address of the newly created created element to be used in the next pass of the loop.
At a glance:
After the first pass of the loop (i = 0) -
5->NULL
After the second pass (i = 1),
4 -> 5 -> NULL
After the third (i = 2),
3 -> 4 -> 5 -> NULL
After the fourth (i = 3),
2 -> 3 -> 4 -> 5 -> NULL
After the fifth (and last) (i = 4),
1 -> 2 -> 3 -> 4 -> 5 -> NULL
The loop builds a linked list of List objects in backwards in memory. The first element is actually the 'ith' element when the list is complete. It is created, given value 'n' and terminated with NULL.
l->val = n
l->next = NULL
The next object is effectively inserted at the front of the list (l->next = l1).
l->val = n-1
l->next ------------> l->val = n
l->next = NULL
And so on, until i=n-1.
Finally (#i=n-1), the last object created is given the value of 1, the loop terminates, and a pointer to the last created object is returned.

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)

Linked list recursive reverse

I was looking at the code below from stanford library:
void recursiveReverse(struct node** head_ref)
{
struct node* first;
struct node* rest;
/* empty list */
if (*head_ref == NULL)
return;
/* suppose first = {1, 2, 3}, rest = {2, 3} */
first = *head_ref;
rest = first->next;
/* List has only one node */
if (rest == NULL)
return;
/* put the first element on the end of the list */
recursiveReverse(&rest);
first->next->next = first;
/* tricky step -- see the diagram */
first->next = NULL;
/* fix the head pointer */
*head_ref = rest;
}
What I don't understand is in the last recursive step for e.g if list is 1-2-3-4 Now for the last recursive step first will be 1 and rest will be 2. So if you set *head_ref = rest .. that makes the head of the list 2 ?? Can someone please explain how after reversing the head of the list becomes 4 ??
Draw out a stack trace...
Intial - {1,2,3,4}
Head - 1
Rest = 2,3,4
Recurse(2,3,4)
Head = 2
Rest = 3,4
Recurse(3,4)
Head = 3
Rest = 4
Recurse (4)
Head = 4
Rest = null //Base Case Reached!! Unwind.
So now we pick up
Recurse(3,4)
Head = 3
Rest = 4
// Return picks up here
first->next->next = first;
so list is:
3,4,3
// set head to null,
null ,4,3,
//Off with his head!
4,3
Return
Now we're here
Recurse(2,3,4)
Head = 2
Rest = 3,4
Previous return leaves state as:
Head = 2 //But Head -> next is still 3! -- We haven't changed that yet..
Rest = 4,3
Head->next is 3,
Head->next->next = 2 makes the list (actually a tree now)
4->3->2
^
|
2
And chop off the head leaving
4->3->2
and return.
Similarly, do the last step which will leave
4->3->2->1
^
|
1
and chop off the head, which removes the one.
Consider the list:
1 -> 2 -> 3 -> 4 -> NULL
^ ^
| |
first rest
Where first points to the first node and rest points to the node next to first.
Since the list is not empty and list does not contain one node we make recursive call to reverse to reverse the list pointed to by rest. This is how the list looks after reversing the rest of the list:
1 -> 2 <- 3 <- 4
^ | ^
| NULL |
first rest
As seen rest now points to the reversed list which has 4 at the beginning and 2 at the end of list. The next pointer of node 2 is NULL.
Now we need to append the first node to the end of the reversed-rest list. To append anything to the end of the list we need to have access to the last node of the list. In this case we need to have access to the last node of the reversed-rest list. Look at the diagram, first -> next points to the last node reversed-rest list. Therefore first -> next -> next will be next pointer of the last node of the reversed-rest list. Now we need to make it point to first so we do:
first -> next -> next = first;
After this step the list looks like:
1 <- 2 <- 3 <- 4
^ -> ^
| |
first rest
Now the next field of the last node of the list must be NULL. But it is not the case now. The next field of the last node ( node 1) is pointing to the node before it ( node 2). To fix this we do:
first -> next = NULL;
After this the list looks like:
NULL <- 1 <- 2 <- 3 <- 4
^ ^
| |
first rest
As seen the list is now correctly reversed with rest pointing to the head of the reversed list.
We need to return the new head pointer so the that changes are reflected in the calling function. But this is a void function and head is passed as double pointer so changing the value of *head will make the calling function see the changed head:
*head = rest;
The rest isn’t 2, it’s 2 -> 3 -> 4, which gets reversed recursively. After that we set *head_ref to rest, which is now (recursively reversed!) 4 -> 3 -> 2.
The important point here is that although both first and rest have the same type, i.e. node*, they are conceptually fundamentally different: first points to one single element, while rest points to a linked list of elements. This linked list is reversed recursively before it gets assigned to *head_ref.
I recently wrote a recursive method for reversing a linked list in ruby. Here it is:
def reverse!( node_1 = #head, node_2 = #head.link )
unless node_2.link
node_2.link = node_1
#head = node_2
return node_1
else
return_node = reverse!(node_1.link, node_2.link)
return_node.link = node_1
node_1.link = nil
return node_1
end
return self
end

Resources