I'm fairly new to C and I am trying to create a function to reverse a linked list, passing only the List itself as a parameter. Is this possible to do without passing a node as a parameter?
Here is my code so far, I know it does not work correctly because I cannot figure out how to make the recursive call on the rest of the list.
void reverse(LL_t *L) {
if (L->head->next == NULL) {
return;
}
node_t *rest = L->head->next;
reverse(rest);
node_t *q = rest->next;
q->next = rest;
rest->next = NULL;
}
As well here are my type definitions.
typedef struct {
node_t *head;
node_t *tail;
} LL_t;
typedef struct _node {
int data;
struct _node *next;
} node_t;
You can reverse the list with a simple loop, recursion is not needed and given your API, not appropriate.
Here is a modified version of your function:
void reverse(LL_t *L) {
node_t *prev = NULL;
node_t *curr = L->head;
L->tail = curr;
while (curr != NULL) {
node_t *next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
L->head = prev;
}
If you are required to use recursion, you can test if the list is empty or limited to a singleton and do nothing, otherwise remove the head element, reverse the resulting list and append the element to the end:
void reverse(LL_t *L) {
if (L->head != L->tail) {
/* at least 2 elements */
node_t *node = L->head;
L->head = node->next;
node->next = NULL;
reverse(L);
L->tail = L->tail->next = node;
}
}
Note that this recursive approach may have undefined behavior if the list is too long as reverse will recurse too many times and cause a stack overflow.
struct node {
int value;
struct node* next;
};
Non-recursive definition operating in constant stack space:
void reverse(struct node** ptr) {
struct node* prev_ptr;
struct node* node_ptr;
if (prev_ptr = * ptr) {
node_ptr = prev_ptr -> next;
prev_ptr -> next = NULL;
while (node_ptr) {
struct node* temp = node_ptr -> next;
node_ptr -> next = prev_ptr;
prev_ptr = node_ptr;
node_ptr = temp;
}
* ptr = prev_ptr;
}
}
Extensionally equivalent recursive definition:
void reverse(struct node** ptr) {
struct node* node_ptr;
if (node_ptr = * ptr) {
node_ptr -> next = NULL;
* ptr = reverse_rec(node_ptr, node_ptr -> next);
}
}
struct node* reverse_rec(struct node* prev_ptr, struct node* node_ptr) {
if (! node_ptr) { return prev_ptr; }
struct node* temp = reverse_rec(node_ptr, node_ptr -> next);
node_ptr -> next = prev_ptr;
return temp;
}
This works, but using recursion to reverse a list requires O(n) stack space overhead. The concept here is to advance the static instance of L->head, while keeping a local copy of head for each level of recursion. Recursion continues until the end of the list is reached, then the list is reversed using the local instances of head as reverse() returns backup the call chain.
void reverse(LL_t *L)
{
node_t *head;
if(L->head == NULL || L->head->next == NULL)
return;
head = L->head;
L->head = head->next;
reverse(L);
head->next->next = head; // reverse the nodes
head->next = NULL;
L->tail = head; // ends up setting tail to what was 1st node
}
//A simple program to reverse a Linked List
void reverse(struct node* head_ref)
{
struct node* first;
struct node* rest;
if (head_ref == NULL)
return;
first = head_ref;
rest = first->next;
if (rest == NULL)
return;
reverse(rest);
first->next->next = first;
first->next = NULL;
head_ref = rest;
}
Related
I'm writing a program to create a linked list(a node), then reverse it. The linked list contains data and the address of the next.
typedef struct node{
int data;
struct node *next;
}node;
Firstly, I create the linked list.
struct node *Insert_value(int dataInput,node* head)
{
node *new_node=NULL;
new_node = malloc(sizeof(node));
new_node -> next = head;
new_node -> data = dataInput;
head = new_node;
return head;
}
After that, i create a function to print these data. (i called it PrintNode)
while(head!= NULL)
{
printf("%d\t",head->data);
head= head->next;
}
printf("\n");
}
Finally, a function created to reverse the linked list.
struct node* Reversing(node **head)
{
node *current, *previous, *first;
current = previous = first = *head;
first = first->next->next;
current = current->next;
previous ->next = NULL;
current->next = previous;
while(first != NULL)
{
previous = current;
current = first;
first = first -> next;
previous->next = current;
}
return current;
}
It's my full program.
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int data;
struct node *next;
}node;
struct node *Insert_value(int dataInput,node* head);
struct node * Reversing(node **head);
void PrintNode(node *head);
main()
{
node *head = NULL;
int i=0,dataInput;
while(i!=5)
{
printf("input your elements: ");
scanf("%d",&dataInput);
head = Insert_value(dataInput,head);
i++;
}
PrintNode(head);
head = Reversing(&head);
PrintNode(head);
}
struct node *Insert_value(int dataInput,node* head)
{
node *new_node=NULL;
new_node = malloc(sizeof(node));
new_node -> next = head;
new_node -> data = dataInput;
head = new_node;
return head;
}
struct node* Reversing(node **head)
{
node *current, *previous, *first;
current = previous = first = *head;
first = first->next->next;
current = current->next;
previous ->next = NULL;
current->next = previous;
while(first != NULL)
{
previous = current;
current = first;
first = first -> next;
previous->next = current;
}
return current;
}
void PrintNode(node* head)
{
while(head!= NULL)
{
printf("%d\t",head->data);
head= head->next;
}
printf("\n");
}
After debugging lots of times, I know that these functions are fine. However, after the reverse function, the address of the next node of the head variable is NULL. Can you explain and give me some pieces of advice?
The one line change that will solve your problem will be (you visualized it a bit wrong).
current->next =previous;
in place of
previous->next = current;
Your code will blowup for single element linked list. Add a proper check for that in the function Reversing(). In case there is single element first->next will be NULL. But you wrote first->next->next which will be undefined behavior in case first->next is NULL.
In earlier case you were just creating a linked list in Reversing() with the links unchanged but head was pointing to the last node. So the next of it was NULL.
Modify Reversing such that new nodes are appended at the end. When going through the list, you need to save the next node ahead of time (node *next = current->next)
struct node* Reversing(node **head)
{
node *current = *head;
node *reverse = NULL;
while(current)
{
node *next = current->next;
if(!reverse)
{
reverse = current;
reverse->next = NULL;
}
else
{
current->next = reverse;
}
reverse = current;
current = next;
}
return reverse;
}
#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
int val;
struct Node* next;
} Node;
void add_at_end(Node* head, int val){
Node* newNode = malloc(sizeof(Node));
newNode -> next = NULL;
Node* temp = head;
if(head -> next == NULL){
head ->val = val;
head -> next = newNode;
}
else{
while(temp -> next != NULL){
temp = temp -> next;
}
temp -> next = newNode;
temp -> val = val;
}
}
void display(Node* l){
while(l->next != NULL){
printf("%d -->", l->val);
l = l->next;
}
printf("End\n");
}
As I said in the question, I'm creating a useless node at the end just to specify NULL. How can I remove that feature? I know I'm doing something wrong in the add_at_end function but I'm not able to rectify it. Help would be appreciated. Thanks
EDIT:
#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
int val;
struct Node* next;
} Node;
typedef struct List{
Node* head;
} List;
void add_at_end(List* l, int val){
Node* newNode = malloc(sizeof(Node));
newNode -> next = NULL;
newNode -> val = val;
Node* temp = l->head;
if(temp == NULL){
l->head = newNode;
}
else{
while(temp->next != NULL){
temp = temp -> next;
}
temp -> next = newNode;
}
}
void display(List* l){
Node* t = l -> head;
while(1){
printf("%d\n", t->val);
if(t->next == NULL) break;
t = t->next;
}
}
int main(){
List l;
l.head = NULL;
add_at_end(&l, 10);
add_at_end(&l, 20);
add_at_end(&l, 30);
display(&l);
return 0;
}
This is my final code.
I need help adding nodes to the middle of the list. How can I do that?
Your node usage is all confused. When you create a new node the value should be stored into that node and the node linked into the list. Instead what you are doing is trying to add the value into the last node and then linking in a dummy node. It's a bit convoluted so I'm not sure I've explained what you have done clearly. Here is what add_to_end should be more like:
add_to_end (Node** head, int val)
{
Node* temp;
Node* newNode = malloc(sizeof(Node));
if (!newNode) {
/* Error */
}
newNode->val = val;
newNode->next = NULL;
if (!*head) {
/* empty list. Just make new node the head */
*head = newNode;
} else {
/* Find the end of the list */
temp = *head;
while (temp->next) {
temp = temp->next;
}
/* temp is now the last node. Chain new node after it */
temp->next = newNode;
}
}
Instead of a null node, you can represent the end of the list with a value of NULL, i.e. with a null pointer. The list is empty when head is NULL and the last node has node->next == NULL.
For this to work, you must be able to update the head when you add a node, because after inserting the frst node, the head will no longer be NULL. (The same goes for inserting at the front or deleting the first node.)
This chan be achieved by passing a pointer to a node pointer:
void add_at_end(Node **head, int val)
{
Node* newNode = malloc(sizeof *newNode);
newNode->next = NULL;
newNode->val = val;
while (*head) {
head = &(*head)->next;
}
*head = newNode;
}
Then you call add_at_and like this:
Node *head = NULL;
add_at_end(&head, 1);
add_at_end(&head, 2);
add_at_end(&head, 3);
It is important that head is initialised to NULL. More generally, all your pointers should either be NULL or point to valid nodes.
#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
int val;
struct Node* next;
} Node;
void add_at_end(Node* head, int val){
Node* newNode = (Node *)malloc(sizeof(Node));
newNode -> next = NULL;
if(head == NULL)
{
head = new_node;
head->val = val;
}
if(head -> next == NULL)
{
new_node ->val = val;
head -> next = newNode;
}
else{
Node *temp = head;
while(temp -> next != NULL){
temp = temp -> next;
}
temp -> next = newNode;
temp -> val = val;
}
}
void display(Node* l){
while(l->next != NULL){
printf("%d -->", l->val);
l = l->next;
}
printf("End\n");
}
For some reason, my code keeps crashing.
If anyone can help me find out why, I would be very thankful.
int destroy(struct node *p)
{
struct node * temp = p;
struct node * next;
while (temp->next != NULL)
{
next = temp->next;
free(temp);
temp = next;
}
p = NULL;
return 1;
}
You need to test temp for null-ness, not temp->next:
void destroy(struct node *p)
{
struct node *temp = p;
while (temp != NULL)
{
struct node *next = temp->next;
free(temp);
temp = next;
}
}
You also don't need to set p to null (it doesn't do anything useful). And returning a status is not a good idea. Your callers either have to test it (but will never see anything other than 1, so the test is pointless), or they have to ignore it (in which case, why bother to return it?). You could do without the variable temp, too:
void destroy(struct node *list)
{
while (list != NULL)
{
struct node *next = list->next;
free(list);
list = next;
}
}
If you really want to set the pointer to null, you have to change the notation:
void destroy(struct node **list)
{
struct node *node = *list;
while (node != NULL)
{
struct node *next = node->next;
free(node);
node = next;
}
*list = NULL;
}
and instead of:
struct node *root = ...;
...
destroy(root);
you would have to write:
struct node *root = ...;
...
destroy(&root);
#include <stdio.h>
#include <stdlib.h>
struct node {
int val;
struct node* next;
} ;
struct node* largest(struct node** first)
{
struct node* largest = *first;
struct node* prev = NULL;
struct node* temp_prev = NULL;
for(;first != NULL; first = first -> next)
{
if (first -> val > largest -> val)
{
largest = first;
prev = temp_prev;
}
temp_prev = first;
}
if(prev != NULL)
prev -> next = largest -> next;
largest -> next = NULL;
return largest;
}
struct node* sel_sort(struct node** list)
{
struct node* head = NULL;
struct node* temp_largest = NULL;
while (*list)
{
head = largest(list);
head->next=temp_largest;
temp_largest = head;
}
*list = head; // note sets the input pointer to the new list.
return head;
}
void print_list(struct node* first)
{
struct node* temp;
for (temp = first; temp != NULL; temp = temp->next)
{
printf("%d\n", temp->val);
}
}
void main() {
struct node* r = malloc(sizeof(struct node));
struct node* s = malloc(sizeof(struct node));
struct node* t = malloc(sizeof(struct node));
struct node* w = malloc(sizeof(struct node));
struct node* q = malloc(sizeof(struct node));
r->val = 2;
r->next = s;
s->val = 10;
s->next = t;
t->next = w;
t->val = 3;
w->val = 1;
w->next = q;
q->val = 6;
q->next = NULL;
printf("\nBefore Sort:\n");
print_list(r);
printf("\nSorted:\n");
struct node* sorted = sel_sort(&r);
print_list(sorted);
}
In short, the above is selection sort for a singly linked list. I'm having an issue where an infinite loops occurs in the sel_sort method, because no matter how many times I call the largest method, one node will be left in the original list. Other then that my code seems to work, but how do I get around this small problem?
So, what do you expect will ever modify the variable list in this while-loop:
struct node* temp = *list;
struct node* head;
struct node* temp_largest = NULL;
while (list != NULL) // <<=== infinite loop
{
head = largest(temp);
head->next=temp_largest;
temp_largest = head;
}
return head;
I question your use of temp. Technically your largest() function should take a list head by address (pointer to pointer), extract the largest node, returning that node after removal from the list, and updating the passed-in list head on the off-chance it was the first node in the list (therefore the head has to be moved):
struct node* head = NULL;
struct node* temp_largest = NULL;
while (*list)
{
head = largest(list);
head->next=temp_largest;
temp_largest = head;
}
*list = head; // note sets the input pointer to the new list.
return head;
And have largest() take a list pointer by address (a double pointer)
struct node* largest(struct node** first)
{
struct node *prev = NULL;
struct node *lprev = NULL;
struct node *cur = NULL;
struct node *largest = NULL;
if (!(first && *first))
return NULL;
// assume the first node is the largest node
largest = lprev = prev = *first;
cur = largest->next;
for(; cur; prev = cur, cur = cur->next)
{
if (cur->val > largest->val)
{
largest = cur;
lprev = prev;
}
}
// go with the simple stuff first. was `largest`
// the first item in the list?
if (largest == *first)
{
// yes it was, so move the list head.
*first = largest->next;
}
else
{ // no it was not, so link `lprev` to be
// the node following `largest`
lprev->next = largest->next;
}
// regardless. always unlink the largest node.
largest->next = NULL;
return largest;
}
Using this in combination with the updated sort, I get this for output:
Output
Before Sort:
2
10
3
1
6
Sorted:
1
2
3
6
10
Going through classic data structures and have stopped on linked lists.Just implemented a circular singly-linked list, but I'm under overwhelming impression that this list could be expressed in a more elegant manner, remove_node function in particular.
Keeping in mind efficiency and code readability, could anybody present a more concise and efficient solution for singly-linked circular list?
#include <stdio.h>
#include <stdlib.h>
struct node{
struct node* next;
int value;
};
struct list{
struct node* head;
};
struct node* init_node(int value){
struct node* pnode;
if (!(pnode = (struct node*)malloc(sizeof(struct node)))){
return NULL;
}
else{
pnode->value = value;
}
return pnode;
}
struct list* init_list(){
struct list* plist;
if (!(plist = (struct list*)malloc(sizeof(struct list)))){
return NULL;
}
plist->head = NULL;
return plist;
}
void remove_node(struct list*a plist, int value){
struct node* current, *temp;
current = plist->head;
if (!(current)) return;
if ( current->value == value ){
if (current==current->next){
plist->head = NULL;
free(current);
}
else {
temp = current;
do {
current = current->next;
} while (current->next != plist->head);
current->next = plist->head->next;
plist->head = current->next;
free(temp);
}
}
else {
do {
if (current->next->value == value){
temp = current->next;
current->next = current->next->next;
free(temp);
}
current = current->next;
} while (current != plist->head);
}
}
void print_node(struct node* pnode){
printf("%d %p %p\n", pnode->value, pnode, pnode->next);
}
void print_list(struct list* plist){
struct node * current = plist->head;
if (!(current)) return;
if (current == plist->head->next){
print_node(current);
}
else{
do {
print_node(current);
current = current->next;
} while (current != plist->head);
}
}
void add_node(struct node* pnode,struct list* plist){
struct node* current;
struct node* temp;
if (plist->head == NULL){
plist->head = pnode;
plist->head->next = pnode;
}
else {
current = plist->head;
if (current == plist->head->next){
plist->head->next = pnode;
pnode->next = plist->head;
}
else {
while(current->next!=plist->head)
current = current->next;
current->next = pnode;
pnode->next = plist->head;
}
}
}
Take a look at the circular linked list in the Linux kernel source: http://lxr.linux.no/linux+v2.6.36/include/linux/list.h
Its beauty derives from the fact that you don't have a special struct for your data to fit in the list, you only have to include the struct list_head * in the struct you want to have as a list. The macros for accessing items in the list will handle the offset calculation to get from the struct list_head pointer to your data.
A more verbose explanation of the linked list used in the kernel can be found at kernelnewbies.org/FAQ/LinkedLists (Sorry, I dont have enough karma to post two hyperlinks).
Edit: Well, the list is a double-linked list and not a single-linked one like you have, but you could adopt the concept and create your own single-linked list.
List processing (particularly of circular lists) gets way easier when you treat the list head like an element of the list (a so-called "sentinel"). A lot of special cases just disappear. You can use a dummy node for the sentinel, but if the next pointer is first in the struct, you don't need to do even that. The other big trick is to keep a pointer to the next pointer of the previous node (so you can modify it later) whenever you modify the list. Putting it all together, you get this:
struct node* get_sentinel(struct list* plist)
{
// use &plist->head itself as sentinel!
// (works because struct node starts with the next pointer)
return (struct node*) &plist->head;
}
struct list* init_list(){
struct list* plist;
if (!(plist = (struct list*)malloc(sizeof(struct list)))){
return NULL;
}
plist->head = get_sentinel(plist);
return plist;
}
void add_node_at_front(struct node* pnode,struct list* plist){
pnode->next = plist->head;
plist->head = pnode;
}
void add_node_at_back(struct node* pnode,struct list* plist){
struct node *current, *sentinel = get_sentinel(plist);
// search for last element
current = plist->head;
while (current->next != sentinel)
current = current->next;
// insert node
pnode->next = sentinel;
current->next = pnode;
}
void remove_node(struct list* plist, int value){
struct node **prevnext, *sentinel = get_sentinel(plist);
prevnext = &plist->head; // ptr to next pointer of previous node
while (*prevnext != sentinel) {
struct node *current = *prevnext;
if (current->value == value) {
*prevnext = current->next; // remove current from list
free(current); // and free it
break; // we're done!
}
prevnext = ¤t->next;
}
}
void print_list(struct list* plist){
struct node *current, *sentinel = get_sentinel(plist);
for (current = plist->head; current != sentinel; current = current->next)
print_node(current);
}
A few comments:
I think the remove function doesn't correctly adjust the circular list pointers when you delete the head node and the list is larger than 3 elements. Since the list is circular you have to point the last node in the list to the new head.
You might be able to shorten the remove function slightly by creating a "find_node" function. Since the list is circular, however, there will still be the edge case of deleting the head node which will be more complex than in a non-circular list.
Code "beauty" is in the eye of the beholder. As code goes yours is easy to read and understand which beats a lot of code in the wild.
I use the following to create a dynamic circular singly linked list. All it requires is the size.
Node* createCircularLList(int size)
{
Node *it; // to iterate through the LList
Node *head;
// Create the head /1st Node of the list
head = it = (Node*)malloc(sizeof(Node));
head->id = 1;
// Create the remaining Nodes (from 2 to size)
int i;
for (i = 2; i <= size; ++i) {
it->next = (Node*)malloc(sizeof(Node)); // create next Node
it = it->next; // point to it
it->id = i; // assign its value / id
if (i == 2)
head->next = it; // head Node points to the 2nd Node
}
// close the llist by having the last Node point to the head Node
it->next = head;
return head; // return pointer to start of the list
}
And i define Node ADT like so:
typedef struct Node {
int id;
struct Node *next;
} Node;