In a job interview I was asked to write a function in C that recursively reverses a linked list, returns the new first node, and doesn't use any new nodes.
How can you do this?
Here's the general idea, in an agnostic language with C-like syntax:
Node invert(Node list, Node acc) {
if (list == null)
return acc;
Node next = list.next;
list.next = acc;
return invert(next, list);
}
The above function receives the first node of the list to be inverted and the accumulated value so far, and returns the head of the newly-inverted list - the reversal of nodes is done in-place, no extra space is allocated (besides a local variable in the stack). Call it like this:
invert(firstNodeOfList, null);
This is an example of a tail recursion: the result gets collected in the acc parameter, and when each recursive call returns, there's nothing left to do, just return the accumulated value.
UPDATE:
In a functional language it's easier and more natural to write a function to reverse a list without using a local variable, for instance look at the following code in Scheme - it has drawback, that it will create a new list node when calling the cons procedure:
(define (invert lst acc)
(if (empty? lst)
acc
(invert (rest lst)
(cons (first lst) acc))))
(invert '(1 2 3 4 5) '())
> '(5 4 3 2 1)
Bottom line: you either create a new node or create a new local variable at each recursive call, but unless the programming language offers an expression for sequential execution and the compiler guarantees evaluation order (see #WillNess' answer) you can't eliminate both and have a working algorithm. Better play it safe and use a temporary variable for enforcing evaluation order and always obtaining correct results.
This is very simple: recurse to the end of the list, passing in the new next pointer each time and returning the end of the list.
struct list {
struct list *next;
};
struct list *reverse(struct list *cur, struct list *prev) {
struct list *next = cur->next;
cur->next = prev;
if(next == NULL) return cur;
return reverse(next, cur);
}
reverse(head, NULL);
I don't know what a "recursively linked list" is so I'll go with your title and assume you want to "reverse a linked list" using a recursive function.
I'll assume it's a singly linked list (so each element has a single pointer next to the next element) and by convention take next = NULL for the last element. For doubly linked lists you have to also deal with the prev pointers but it is basically the same idea. With a doubly linked list it is simpler since you don't even need to keep track of the previous element; you just have to flip the two pointers around on each element.
To reverse the list we can imagine walking down it an element at a time, flipping the next pointers to point to the previous element as we go. This is easy enough to write as a recursive function which takes as parameters a pointer to the current element and a pointer to the previous element (at the start this pointer is NULL).
node* reverseList(node* head, node* prev = NULL) {
if (head == NULL) return prev;
std::swap(head->next, prev); // prev points to next element to process
return reverseList(prev, head);
}
Hey guys please find the programs for reverse linked list with and without recursion below
LINK *reverse_linked_list_recursion(LINK *head)
{
LINK *temp;
if (!head) {
printf("Empty list\n");
return head;
}
else if (!head->next)
return head;
temp = reverse_linked_list_recursion(head->next);
head->next->next = head;
head->next = NULL;
return temp;
}
LINK *reverse_linked_list_without_recursion(LINK *head)
{
LINK *new, *temp;
if (!head) {
printf("No element in the list\n");
return head;
}
else {
new = head;
while (head->next) {
temp = head->next;
head->next = temp->next;
temp->next = new;
new = temp;
}
}
return new;
}
So, the variation on Óscar López's answer here is
Node invert(Node list, Node acc)
{
if (!list)
return acc;
return invert(list.next, ((list.next=acc),list));
}
The sequence of expressions (a,b) returns its last value and is evaluated left-to-right.
This will only work for compilers which guarantee evaluation order of function's arguments as left-to-right. If it is right-to-left, the arguments to invert should be swapped.
If the evaluation order is nondeterministic, this will not work. The C standard apparently leaves this order unspecified, but some compilers might have their own way with it. You may know this about your compiler, but it is non-portable, and your compiler may change this in the future too. Writing such code is frowned upon. Maybe that is what your interviewers wanted to hear from you. They like such tricks, and want to see how you respond.
The normal way to control evaluation order is by using temporary variables.
Related
I'm curious what base case can be used to recursively free a circular linked list, passing the head of the linked list as the only parameter. I originally thought a base case could be if (head->next == head) { return NULL; } could be sufficient to prevent head->next from pointing to itself, but this doesn't seem to be the case (literally and figuratively). The last node free(Head) is not being freed after the recursive calls here.
typedef struct node
{
int data;
struct node *next;
} node;
// temp stores the original head of the list
node *recursive_destroyer(node *head, node *temp)
{
if (head->next == temp)
return NULL;
recursive_destroyer(head->next, temp);
free(head);
head = NULL;
return NULL;
}
You asked about passing in one parameter
I think most people skipped your first sentence, and jumped to your code. You ask in your post:
I'm curious what base case can be used to recursively free a circular linked list, passing the head of the linked list as the only parameter. ...
You go on to explain the approach you tried:
I originally thought a base case could be if (head->next == head) { return NULL; } could be sufficient to prevent head->next from pointing to itself, but this doesn't seem to be the case ...
You provide a code example, but it passes in two parameters.
Remove head->next, not head
This answer is addressing the question in your first sentence. A short comparison with your approach will follow.
Checking to see if head->next points to head is a fine stopping case, but it means your recursive function needs to remove and destroy head->next at each iteration, and then recursively process the same list.
If head->next and head are the same, then destroy head, and you are done.
I don't see any point of returning a value from this function, so I removed it.
void recursive_destroyer(node *head) {
if (head == NULL) return;
if (head->next == head) {
destroy(head);
return;
}
node *tmp = head->next;
head->next = head->next->next;
destroy(tmp);
recursive_destroyer(head);
}
Notice there is no longer any need for a second parameter to the recursive function.
Comparison with your approach
There are some issues in your sample code that caused erroneous behavior. There are other answers that have addressed them with some depth. But, I did want to point out that you should prefer tail recursion whenever possible.
Tail recursion is a special case of a sibling call. A sibling call is when a function calls another function, and then immediately returns. In the example below, function_A() is making a sibling call to function_B()
void function_B () { puts(__func__); }
void function_A (bool flag) {
if (flag) {
function_B();
return;
}
puts(__func__);
}
A sibling call can be optimized by the compiler to reuse the stack frame of the current function to make the sibling call. This is because none of the current function state of the caller is needed after the sibling returns.
A tail recursive call can be optimized in the same way. Thus, the tail recursive call when optimized has the same memory footprint as an ordinary loop. And in fact, if the optimizer detects the sibling call is a recursive call, instead of performing a function call to itself, the tail recursion is converted into a jump to the start of the function. Most C compilers can perform this optimization. You can manually perform this optimization yourself, and easily convert a tail recursive function into a loop.
If you are using the optimization features of your C compiler, and it supports tail recursion optimization, then there is no technical reason to prefer a loop over tail recursion. If your software team finds reading recursive code confusing, then loops are preferred just to make the code easier to comprehend.
I wasn't setting the head equal to the recursive_destroyer function inside another function that frees the entire list. Here is that function:
LinkedList *destroy_list(LinkedList *list)
{
node *temp;
if (list == NULL)
return NULL;
if (list->head == NULL)
return NULL;
temp = list->head;
// was not setting list->head equal to this function.
// causing the original head to never become NULL
list->head = recursive_destroyer(list->head, temp);
if (list->head != NULL)
printf("Error, head not freed.. \n");
free(list);
return NULL;
}
Could have also passed a pointer to list->head to avoid setting list->head equal to the function.
Your code does not work. It will leave a single allocation intact.
Consider the circular linked list [1]. If you call recursive_destroyer(head, head), it will not free anything. The correct recursive code would be
void destroy_helper(node* const current, node* const original) {
if (current->next != original) destroy_helper(current->next, original);
free(current);
}
void destroy(node* const list) {
// null-check necessary since otherwise current->next is UB in destroy_helper
if (list) destroy_helper(list, list);
}
If we want to turn this into iterative code, we must first modify the destroy_helper function to be tail-recursive:
void destroy_helper(node* const current, node* const original) {
node* const next = current->next;
free(current);
if (next != original) destroy_helper(next, original);
}
which we can then rewrite to a loop:
void destroy(node* const list) {
if (list) {
node* current = list;
do {
node* next = current->next;
free(current);
current = next;
} while (current != list);
}
}
Edit:
To prove that my code is actually freeing everything, we can replace free with the following function:
void free_with_print(node* ptr) {
printf("Freeing node with value %d\n", ptr->data);
free(ptr);
}
A simple example:
int main() {
node* node1 = malloc(sizeof *node1);
node1->data = 1;
node1->next = node1;
node* node2 = malloc(sizeof *node2);
node2->data = 2;
node2->next = node1;
node1->next = node2;
destroy(node1);
}
using the iterative version prints
Freeing node with value 1
Freeing node with value 2
as expected. Trying the same thing with your original code prints
Freeing node with value 1
As expected, your code does not free one of the two nodes, while mine frees both.
For code like this you can (and should) do "single step debugging" in your head to convince yourself it should work as intended. This is a very important skill to learn.
Let's try 3 cases:
a) Imagine that the list is empty (head and temp are NULL). In this case it would crash at if (head->next == temp) due to trying to use a NULL pointer in head->next.
b) Imagine that the list has one item. In this case if (head->next == temp) is true because it's a circular linked list, so it returns from the first invocation without freeing anything.
c) Imagine the list has 2 items. In this case if (head->next == temp) is false for the first invocation and true for the second invocation; so the second invocation will free nothing and the first invocation will free the original head of the list.
We can extrapolate from that and say that the last item on the list is never freed (but the first item at the original head of the list will be freed if it's not also the last item).
To fix that you could always free the item, like:
if (head->next == temp) {
free(head);
return NULL;
}
This is messy because you're duplicating code (and could invert the condition to avoid that). It would also be easier to read if head always points to the original head and temp was temporary. Also (as mentioned in comments) there's no point returning NULL when it finishes. Refactoring the code gives you something like:
void recursive_destroyer(node *head, node *temp)
{
if (head->next != temp) {
recursive_destroyer(head, temp->next);
}
free(temp);
}
However; this still crashes if the list is originally empty. To fix that I'd do a wrapper function, like:
void recursive_destroyer(node *head) {
if(head != NULL) {
recursive_destroyer_internal(head, head);
}
}
static void recursive_destroyer_internal(node *head, node *temp)
{
The final problem is that recursion is bad (tends to be slower due to all the extra function calls, and has a risk of crashing when you run out of stack space, and often ends up harder for people to read); especially if/when the compiler can't do "tail call optimization" itself to convert it into a non-recursive loop. To fix that you shouldn't be using recursion. E.g.:
void destroy(node *head) {
node *original_head = head;
node *temp;
if(head != NULL) {
do {
temp = head;
head = head->next;
free(temp);
} while(head != original_head);
}
}
I came up with this way of creating a linked list in C:
void queue(Node ** head, Node * object)
{
Node * tmp = (Node *)malloc(sizeof(Node));
*tmp = *object;
Node *last = get_Last((*head));
if (last) {
last->next = tmp;
tmp->next = NULL;
}
else {
(*head) = tmp;
tmp->next = NULL;
}
}
The idea is rather simple, pass a pointer to an object to queue(...) then traverse the list to find the last node and then edit a few pointers. However what I don't exactly like is the get_Last(...) function:
Node * get_Last(Node * head)
{
if (!head) {
return NULL;
}
while (head->next) {
head = head->next;
}
return head;
}
This function means that should queue(...) ever find itself in a loop then the algorithm I came up with has O(n²) time complexity which is just too much for something as simple as creating a linked list. What can be done to bring down the complexity to O(n)? I guess queue(...) still needs the address of the last node, but how do I obtain it without a loop?
Are you sure that items need to be inserted at the end of the list? Inserting/removing at the front of a linked list is O(1) for free.
If you do in fact want an efficient FIFO list, the best way to do this by far is to keep the address of the tail element. It requires only constant memory and allows O(1) inserts to the tail.
The most clear way to accomplish this would likely be to make a Queue struct that keeps a pointer to the head and tail, with utility functions accepting a pointer to Queue for enqueue and dequeue operations.
I am understanding recursion and so I tried writing reverse a linked list program. I have written the below function but it says segmentation error (core dumped).
void reverse(){
if (head -> next == NULL){
return;
}
reverse (head -> next);
struct node *q = (struct node*) malloc (sizeof(struct node));
q = head -> next;
q -> next = head;
head -> next = NULL;
}
Please can someone guide me. Thank you.
Shouldn't reverse take an argument? And please be aware that you cannot change a pointer in a function and have that be a lasting change. That is, in a C function, the only lasting changes are those that use *var = something.
Recursion is a way of thinking that's gained by practice. So congratulations on your attempt. It's not correct, but don't be discouraged.
Here are two ways to go about the problem.
Your goal is to subdivide it into a smaller version of itself plus a (hopefully easy and fast to compute) incremental step that takes a solution to the smaller version to a complete solution. This is the essence of recursive thinking.
First try: Think of the list as a head element plus the "rest of the list." I.e.,
L = empty or
= h . R
where h is the head element R is the rest of the list, and dot . is joining a new element to the list. Reversing this list consists of reversing R, then appending h on the end:
rev(L) = empty if L is empty
= rev(R) . h otherwise
This is a recursive solution because we can call the reverse function recursively to solve the slightly smaller problem of reversing R, then add a little work to append h, and that gives us the complete solution.
The problem with this formulation is that appending h is more expensive than you'd like. Since we have a singly linked list with only a head pointer, it's time consuming: traverse the whole list. But it will work fine. In C it would be:
NODE *rev(NODE *head) {
return head ? append(head, rev(head->next)) : NULL;
}
NODE *append(NODE *node, NODE *lst) {
node->next = NULL;
if (lst) {
NODE *p;
for (p = lst; p->next; p = p->next) /* skip */ ;
p->next = node;
return lst;
}
return node;
}
So how to get rid of the bad performance? It's frequently the case that different recursive formulations of a problem have different efficiencies. So some trial and error is often involved.
Next try: Think about the computation in terms of dividing the list into two sublists: L = H T, so rev(L) = rev(T) + rev(H). Here plus + is list concatenation. The key is that if I know rev(H) and want to add a new element at its head, the element to add is the first element in T. If this seems fuzzy, let H = [a, b, c] and T = [d, e]. Then if I already know rev(H) = [c, b, a] and want to prepend the next element at the head, I want d, which is the first element of T. In our little notation, you can write this observation just so:
rev(H + (d . T)) = rev(T) + ( d . rev(H) )
So this looks very good. In both cases (getting the head of T and moving it to the head of rev(H)), I'm only interested in the head of the list, which is very efficient to access.
Of course if T is empty, then rev(H) = rev(L). This is the answer!
Writing this as recursive procedure.
NODE *rev(NODE *t, NODE *rev_h) {
if (t) { // if t has some elements
NODE *tail = t->next; // save the tail of T
t->next = rev_h; // prepend the head to rev(H)
return rev(tail, t); // recur to solve the rest of the problem
}
return rev_h; // otherwise T is empty, so the answer is rev(H)
}
At the start, we don't know anything at all about rev(H), so T is the whole list:
NODE *reversed_list = rev(list, NULL);
The next thing to note is that this function is tail recursive: the recursive call is executed just before the function returns. This is good! It means we can easily rewrite it as a loop:
NODE *rev(NODE *t, NODE *rev_h) {
recur:
if (t) { // if t has some elements
NODE *tail = t->next; // save the tail of T
t->next = rev_h; // prepend the head to rev(H)
rev_h = t; // "simulate" the recursive call
t = tail; // by setting both args
goto recur; // and going back to the start
}
return rev_h; // otherwise T is empty, so the answer is rev(H)
}
You can always do this transformation with tail-recursive calls. You should think hard about why this works.
Now the goto is easily rewritten as a while loop, and we can make rev_h a local variable initialized to NULL, since that's all the initial call does:
NODE *rev(NODE *t) {
NODE *rev_h = NULL;
while (t) { // while t has some elements
NODE *tail = t->next; // save the tail of T
t->next = rev_h; // prepend the head to rev(H)
rev_h = t; // "simulate" the recursive call
t = tail; // by setting both args
}
return rev_h; // otherwise T is empty, so the answer is rev(H)
}
An in-place linked list reverser that needs only a small constant amount of space!
And look! We never had to draw funny box and arrow diagrams or think about pointers. It "just happened" by careful reasoning about how to subdivide the problem into smaller instances of itself, the essence of recursion. It's also a nice way to see that loops are just a special kind of recursion. Cool, no?
I am assuming that you have something like the followings predefined in your .c file
typedef struct node node_t;
struct node {
int some_data;
node_t *next;
};
/* Your linked list here */
typedef struct {
node_t *head;
node_t *foot; /* to keep track of the last element */
} list_t;
In your function, there are a few mistakes you made
not providing any input arguments
access head->next when the program has no idea where to find head
Hence, resulting in the most frustrating error in C -- segmentation fault!
Instead, you should try the following:
void reverse(list_t *mylinkedlist){
if (mylinkedlist->head->next == NULL) {
return;
}
/* do something */
}
I want to write a function which gets a pointer to a header of a linked list and deletes from the list every second member of it. The List is a linked elements of type element:
typedef struct element{
int num;
struct element* next;
}element;
I'm new to all these pointers arithmetic so I'm not sure I write it correctly:
void deletdscnds(element* head) {
element* curr;
head=head->next; //Skipping the dummy head//
while (head!=NULL) {
if (head->next==NULL)
return;
else {
curr=head;
head=head->next->next; //worst case I'll reach NULL and not a next of a null//
curr->next=head;
}
}
}
I kept changing it since I kept finding errors. Can you please point out any possible errors?
The algorithm is a lot simpler if you think of your linked list in terms of node pairs. Each iteration of your loop should process two nodes - head and head->next, and leave head equal to head->next->next upon exit. It is also important to not forget deleting the middle node, if you are cutting it out of the list, otherwise you are going to see memory leaks.
while (head && head->next) {
// Store a pointer to the item we're about to cut out
element *tmp = head->next;
// Skip the item we're cutting out
head->next = head->next->next;
// Prepare the head for the next iteration
head = head->next;
// Free the item that's no longer in the list
free(tmp);
}
It might be most straightforward to visualize this problem in recursive terms, like this:
// outside code calls this function; the other functions are considered private
void deletdscnds(element* head) {
delete_odd(head);
}
// for odd-numbered nodes; this won't delete the current node
void delete_odd(element* node) {
if (node == NULL)
return; // stop at the end of the list
// point this node to the node two after, if such a node exists
node->next = delete_even(node->next);
}
// for even-numbered nodes; this WILL delete the current node
void delete_even(element* node) {
if (node == NULL)
return NULL; // stop at the end of the list
// get the next node before you free the current one, so you avoid
// accessing memory that has already been freed
element* next = node->next;
// free the current node, that it's not needed anymore
free(node);
// repeat the process beginning with the next node
delete_odd(next);
// since the current node is now deleted, the previous node needs
// to know what the next node is so it can link up with it
return next;
}
For me, at least, this helps clarify what needs to be done at each step.
I wouldn't advise actually using this method because, in C, recursive algorithms may take up a lot of RAM and cause stack overflows with compilers that don't optimize them. Rather, dasblinkenlight's answer has the code that you should actually use.
I'm having trouble reversing my doublely linked deque list (with only a back sentinel) in C, I'm approaching it by switching the pointers and here is the code I have so far:
/* Reverse the deque
param: q pointer to the deque
pre: q is not null and q is not empty
post: the deque is reversed
*/
/* reverseCirListDeque */
void reverseCirListDeque(struct cirListDeque *q)
{
struct DLink *back = q->backSentinel;
struct DLink *second = q->backSentinel->prev;
struct DLink *third = q->backSentinel->next;
while (second != q->backSentinel->next){
back->next = second;
third = back->prev;
back->next->prev = back;
back = second;
second = third;
}
}
But it doesn't seem to work, I've been testing it with a deque that looks like this: 1, 2, 3
The output is: 3 and this process seems to mess up the actual value of the numbers. ie. 2 becomes 2.90085e-309... I think the pointer switching is messed up but I cannot find the problem. And even though it doesn't mean my code is correct; it compiles fine.
Linked structures like deques lend themselves readily to recursion, so I tend to favor a recursive style when dealing with linked structures. This also allows us to write it incrementally so that we can test each function easily. Looping as your function does has many downsides: you can easily introduce fencepost errors and it tends toward large functions that are confusing.
First, you've decided to do this by swapping the pointers, right? So write a function to swap pointers:
void swapCirListDequePointers(
struct cirListDeque** left,
struct cirListDeque** right)
{
struct cirListDeque* temp = *left;
*left = *right;
*right = temp;
}
Now, write a function that reverses the pointers in a single node:
void swapPointersInCirListDeque(struct cirListDeque* q)
{
swapCirListDequePointers(&(q->prev),&(q->next));
}
Now, put it together recursively:
void reverseCirListDeque(struct cirListDeque* q)
{
if(q == q->backSentinel)
return;
swapPointersInCirListDeque(q);
// Leave this call in tail position so that compiler can optimize it
reverseCirListDeque(q->prev); // Tricky; this used to be q->next
}
I'm not sure exactly how your struct is designed; my function assumes that your deque is circular and that you'll be calling this on the sentinel.
EDIT: If your deque isn't circular, you'll want to call swapPointersInCirListDeque(q) on the sentinel as well, so move swapPointersInCirListDeque(q) before the if statement.
If you plan to use the backSentinel after this, you should change that also, since it's now the front of the list. If you have a frontSentinel, you can just add swapCirListDequePointers(&(q->frontSentinel),&(q->backSentinel)); to swapPointersInCirListDeque. Otherwise, you'll have to pass in the first node along with q and set q->backSentinel to that.
If it's a doubly linked list, you shouldn't need to change any pointers at all. Just swap over the payloads:
pointer1 = first
pointer2 = last
while pointer1 != pointer2 and pointer2->next != pointer1:
temp = pointer1->payload
pointer1->payload = pointer2->payload
pointer2->payload = temp
pointer1 = pointer1->next
pointer2 = pointer2->prev
If by back sentinel you mean the last pointer (as in no first pointer is available), then you need to step backwards throw the deque to find it. It's hard to believe however that this would be the case since it would be a fairly inefficient deque (which is supposed to be a double ended queue).
You've been given a couple of suggestions already; here's another possibility:
// Assumes a node something like:
typedef struct node {
struct node *next, *prev;
int data;
} node;
and also assumes a couple of variables (globals for the moment) named head and tail that point to the head and tail of the deque, respectively.
void reverse() {
node *pos = head;
node *temp = pos->next;
head = tail;
tail = pos;
while (pos != NULL) {
node *t = pos->prev;
pos->prev = pos->next;
pos->next = t;
pos = temp;
if (temp)
temp = temp->next;
}
}
At least for the moment, this does not assume any sentinels -- just NULL pointers to signal the ends of the list.
If you're just storing ints in the deque, Paxdiablo's suggestion is a good one (except that creating a doubly-linked node to hold only an int is a massive waste). Assuming that in reality you were storing something large enough for doubly-linked nodes to make sense, you'd also prefer to avoid moving that data around any more than necessary, at least as a general rule.