Adding a node to the head of the linked list - c

I would like to add a node in a sorted linked list based on the number. This is the struct:
struct node {
int number;
struct node *next;
}
I am able to add to the sorted linked list correctly but can't get it to change head.
Unfortunately I can't change the format of the function declaration so this is my function:
int create(struct node *head, int number) {
struct node *newNode = malloc(sizeof(struct node));
newNode->number = number;
struct node *current = head;
if (current->number == -1) {
newNode->next = NULL;
*head= *newNode;
return 1;
}
//Checking if head's number is bigger than init
if (current->number > number) {
newNode->next = current;
*head = *newNode;
} else {
while(current->next != NULL && (current->number <= number)) {
current = current->next;
}
newNode->next = current->next;
current->next = newNode;
}
return 1;
}
the call to the function is (Note I also can't change this):
struct node *list;
list = initializeList();
int num;
num = create(list, 5);
num = create(list, 1);
After the second call, the list should be 1->5. But it becomes 1->1->1->1->.....
Edit: Code to Initialize list:
struct node * initializeList() {
struct node *head;
head = malloc(sizeof(struct node));
head->next = NULL;
head->number = -1;
return head;
}

I made a few edits to the create function to fix the problem.
First, if the head of the list has number == -1 then no new node should be allocated, since you are just replacing the number.
Second, if you need to insert a node, the previous node needs to know where to the next node goes, so you can't just replace the previous node with the new node. You need to either point the previous node to the new node and point the new node to the displaced node; or you can copy the current node into the new node, and put the number for the new node into the current, and point it to the new node. The second works better here, since it does not require changing the head (which we can't do if it needs to go at the front).
int create(struct node *head, int number) {
struct node *current = head;
if (current->number == -1) {
current->number = number;//just replace the number, no need for anything else
return 1;
}
//allocate only if we must insert
struct node *newNode = malloc(sizeof(struct node));
//no longer need to check if head
while(current->next != NULL && (current->number <= number)) {
current = current->next;
}
if(current->next == NULL && current->number < number) {//check if number needs to go at the end
current->next = newNode;
newNode->next = NULL;
newNode->number = number;
} else {
*newNode = *current;//newNode will go after current, but with current's values
current->number = number;//replace current with the number to "insert" it
current->next = newNode;//point to the next node
}
return 1;
}

assign an index value to the node and shift the other elements by one. I mean you can add one to the each value of the other element and make in iterate in a loop.

Related

Removing unique elements in a doubly linked list in C

I need a little help removing unique characters in a doubly linked list in C. So here's the logic I tried implementing: I counted the occurrence of each character in the doubly linked list. If it's occurrence is 1 time, then it is unique element and needs to be deleted. I'll be repeating the process for all elements. But my code in remove_unique_dll() function isn't working properly, please help me fix it. Here's my code-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char data;
struct node *next;
struct node *prev;
};
struct node *head, *tail = NULL; //Represent the head and tail of the doubly linked list
int len;
void addNode(char data)
{
struct node *newNode = (struct node*) malloc(sizeof(struct node)); //Create new node
newNode->data = data;
if (head == NULL)
{ //If dll is empty
head = tail = newNode; //Both head and tail will point to newNode
head->prev = NULL; //head's previous will point to NULL
tail->next = NULL; //tail's next will point to NULL, as it is the last node of the list
}
else
{
tail->next = newNode; //newNode will be added after tail such that tail's next points to newNode
newNode->prev = tail; //newNode's previous will point to tail
tail = newNode; //newNode will become new tail
tail->next = NULL; //As it is last node, tail's next will point to NULL
}
}
void remove_unique_dll()
{
struct node *current = head;
struct node *next;
struct node *prev;
int cnt;
while (current != NULL)
{
next = current->next;
cnt = 1;
//printf("!%c ",next->data);
while (next != NULL)
{
if (next->data == current->data)
{
cnt += 1;
next = next->next;
}
else
next = next->next;
//printf("#%c %d %c\n",next->data,cnt,current->data);
}
if (cnt == 1)
{
prev = current->prev;
//printf("#%c %d",prev->data,cnt);
if (prev == NULL)
{
head = next;
}
else
{
prev->next = next;
}
if (next == NULL)
{
tail = prev;
}
else
{
next->prev = prev;
}
}
current = current->next;
//printf("#%c ",current->data);
}
head = current;
}
void display()
{
struct node *current = head; //head the global one
while (current != NULL)
{
printf("%c<->", current->data); //Prints each node by incrementing pointer.
current = current->next;
}
printf("NULL\n");
}
int main()
{
char s[100];
int i;
printf("Enter string: ");
scanf("%s", s);
len = strlen(s);
for (i = 0; i < len; i++)
{
addNode(s[i]);
}
printf("Doubly linked list: \n");
display();
remove_unique_dll();
printf("Doubly linked list after removing unique elements: \n");
display();
return 0;
}
The output is like this-
If you uncomment the printf() statements inside remove_unique_dll() you'll notice that no code below inner while loop is being executed after inner while loop ends. What's the issue here and what's the solution?
Sample input- aacb
Expected output- a<->a<->NULL
Some issues:
You shouldn't assign head = current at the end, because by then current is NULL
The next you use in the deletion part is not the successor of current, so this will make wrong links
As you progress through the list, every value is going to be regarded as unique at some point: when it is the last occurrence, you'll not find a duplicate anymore, as your logic only looks ahead, not backwards.
When you remove a node, you should free its memory.
Not a big issue, but there is no reason to really count the number of duplicates. Once you find the first duplicate, there is no reason to look for another.
You should really isolate the different steps of the algorithm in separate functions, so you can debug and test each of those features separately and also better understand your code.
Also, to check for duplicates, you might want to use the following fact: if the first occurrence of a value in a list is the same node as the last occurrence of that value, then you know it is unique. As your list is doubly linked, you can use a backwards traversal to find the last occurrence (and a forward traversal to find the first occurrence).
Here is some suggested code:
struct node* findFirstNode(char data) {
struct node *current = head;
while (current != NULL && current->data != data) {
current = current->next;
}
return current;
}
struct node* findLastNode(char data) {
struct node *current = tail;
while (current != NULL && current->data != data) {
current = current->prev;
}
return current;
}
void removeNode(struct node *current) {
if (current->prev == NULL) {
head = current->next;
} else {
current->prev->next = current->next;
}
if (current->next == NULL) {
tail = current->prev;
} else {
current->next->prev = current->prev;
}
free(current);
}
void remove_unique_dll() {
struct node *current = head;
struct node *next;
while (current != NULL)
{
next = current->next;
if (findFirstNode(current->data) == findLastNode(current->data)) {
removeNode(current);
}
current = next;
}
}
You have at least three errors.
After counting the number of occurrences of an item, you use next in several places. However, next has been used to iterate through the list. It was moved to the end and is now a null pointer. You can either reset it with next = current->next; or you can change the places that use next to current->next.
At the end of remove_unique_dll, you have head=current;. There is no reason to update head at this point. Whenever the first node was removed from the list, earlier code in remove_unique_dll updated head. So it is already updated. Delete the line head=current;.
That will leave code that deletes all but one occurrence of each item. However, based on your sample output, you want to leave multiple occurrences of items for which there are multiple occurrences. For that, you need to rethink your logic in remove_unique_dll about deciding which nodes to delete. When it sees the first a, it scans the remainder of the list and sees the second, so it does not delete the first a. When it sees the second a, it scans the remainder of the list and does not see a duplicate, so it deletes the second a. You need to change that.
Let's consider your code step by step.
It seems you think that in this declaration
struct node *head, *tail = NULL; //Represent the head and tail of the doubly linked list
the both pointers head and tail are explicitly initialized by NULL. Actually only the pointer tail is explicitly initialized by NULL. The pointer head is initialized implicitly as a null pointer only due to placing the declaration in file scope. It to place such a declaration in a block scope then the pointer head will be uninitialized.
Instead you should write
struct node *head = NULL, *tail = NULL; //Represent the head and tail of the doubly linked list
Also it is a very bad approach when the functions depend on these global variables. In this case you will be unable to have more than one list in a program.
Also the declaration of the variable len that is used only in main as a global variable
int len;
also a bad idea. And moreover this declaration is redundant.
You need to define one more structure that will contain pointers head and tail as data members as for example
struct list
{
struct node *head;
struct node *tail;
};
The function addNode can invoke undefined behavior when a new node can not be allocated
void addNode(char data)
{
struct node *newNode = (struct node*) malloc(sizeof(struct node)); //Create new node
//...
You should check whether a node is allocated successfully and only in this case change its data members. And you should report the caller whether a node is created or not.
So the function should return an integer that will report an success or failure.
In the function remove_unique_dll after this while loop
while (next != NULL)
{
if (next->data == current->data)
{
cnt += 1;
next = next->next;
}
else
next = next->next;
//printf("#%c %d %c\n",next->data,cnt,current->data);
}
if cnt is equal to 1
if (cnt == 1)
//..
then the pointer next is equal to NULL. And using the pointer next after that like
if (prev == NULL)
{
head = next;
}
else
{
prev->next = next;
}
is wrong.
Also you need to check whether there is a preceding node with the same value as the value of the current node. Otherwise you can remove a node that is not a unique because after it there are no nodes with the same value.
And this statement
head = current;
does not make sense because after the outer while loop
while (current != NULL)
the pointer current is equal to NULL.
Pay attention that the function will be more useful for users if it will return the number of removed unique elements.
Here is a demonstration program that shows how the list and the function remove_unique_dll can be defined.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char data;
struct node *next;
struct node *prev;
};
struct list
{
struct node *head;
struct node *tail;
};
int addNode( struct list *list, char data )
{
struct node *node = malloc( sizeof( *node ) );
int success = node != NULL;
if (success)
{
node->data = data;
node->next = NULL;
node->prev = list->tail;
if (list->head == NULL)
{
list->head = node;
}
else
{
list->tail->next = node;
}
list->tail = node;
}
return success;
}
size_t remove_unique_dll( struct list *list )
{
size_t removed = 0;
for ( struct node *current = list->head; current != NULL; )
{
struct node *prev = current->prev;
while (prev != NULL && prev->data != current->data)
{
prev = prev->prev;
}
if (prev == NULL)
{
// there is no preceding node with the same value
// so the current node is possibly unique
struct node *next = current->next;
while (next != NULL && next->data != current->data)
{
next = next->next;
}
if (next == NULL)
{
// the current node is indeed unique
struct node *to_delete = current;
if (current->prev != NULL)
{
current->prev->next = current->next;
}
else
{
list->head = current->next;
}
if (current->next != NULL)
{
current->next->prev = current->prev;
}
else
{
list->tail = current->prev;
}
current = current->next;
free( to_delete );
++removed;
}
else
{
current = current->next;
}
}
else
{
current = current->next;
}
}
return removed;
}
void display( const struct list *list )
{
for (const node *current = list->head; current != NULL; current = current->next)
{
printf( "%c<->", current->data );
}
puts( "null" );
}
int main()
{
struct list list = { .head = NULL, .tail = NULL };
const char *s = "aabc";
for (const char *p = s; *p != '\0'; ++p)
{
addNode( &list, *p );
}
printf( "Doubly linked list:\n" );
display( &list );
size_t removed = remove_unique_dll( &list );
printf( "There are removed %zu unique value(s) in the list.\n", removed );
printf( "Doubly linked list after removing unique elements:\n" );
display( &list );
}
The program output is
Doubly linked list:
a<->a<->b<->c<->null
There are removed 2 unique value(s) in the list.
Doubly linked list after removing unique elements:
a<->a<->null
You will need at least to write one more function that will free all the allocated memory when the list will not be required any more.

Insert a node into a doubly linked list in a sorted manner?

I am working on a problem in which I have a method that is supposed to insert a node into a doubly linked list in a sorted manner. Here is my node and list structure:
typedef struct NodeStruct Node;
//struct for each office item
struct NodeStruct {
int id;
struct NodeStruct *next;
struct NodeStruct *prev; //Create doubly linked list node
};
/** Structure for the whole list, including head and tail pointers. */
typedef struct {
/** Pointer to the first node on the list (or NULL ). */
Node *head;
Node *last;
} List;
When I attempt to print the list of items, the item what I am trying to insert does not appear. For instance, if I try to insert 15 into this list
1 -> 2 -> 3 -> 5 -> 7,
15 does not appear at the end. Here is my insert method:
void insert(int idInsert, List *list)
{
//Initialize data for node
int idInsert;
//Insert the record based on the ID if no duplicates exist
//Special case: insert at front if idInsert is less than the ID of the current head
if (idInsert < list->head->id) {
//Make the node with idInsert the first node
Node *new = (Node *)malloc(sizeof(Node)); //Allocate memory for the new node
//Add in data
new->id = idInsert;
new->next = list->head;
list->head = new;
} else { //Locate the node before the point of insertion
//Allocate memory for the node
Node *new = (Node *)malloc(sizeof(Node));
//Add in data
new->id = idInsert;
Node *current = list->head;
while (current->next != NULL && current->next->id < new->id) {
current = current->next;
}
new->next = current->next;
if (current->next != NULL) {
new->next->prev = new;
}
current->prev->next = new;
new->prev = current;
}
//Print this message if successful
printf("RECORD INSERTED: %d\n", idInsert);
}
I am also going to include some minimal reproducible code below:
#include <stdlib.h>
#include <stdio.h>
typedef struct NodeStruct Node;
//struct for each office item
struct NodeStruct {
int id;
struct NodeStruct *next;
struct NodeStruct *prev; //Create doubly linked list node
};
/** Structure for the whole list, including head and tail pointers. */
typedef struct {
/** Pointer to the first node on the list (or NULL ). */
Node *head;
Node *last;
} List;
List *list;
List *makeList();
void insert(int idInsert, List *list);
static void *addRecord(List *list, int newID);
static void printReverse(List *list);
int main(int argc, char **argv) {
//Create an empty list for you to start.
list = (List *)makeList();
addRecord(list, 1);
addRecord(list, 2);
addRecord(list, 3);
addRecord(list, 4);
addRecord(list, 7);
insert(15, list);
printReverse(list);
}
List *makeList()
{
List *list = (List *) malloc( sizeof( List ) );
list->head = NULL;
list->last = NULL;
return list;
}
void insert(int idInsert, List *list)
{
//Insert the record based on the ID if no duplicates exist
//Special case: insert at front if idInsert is less than the ID of the current head
if (idInsert < list->head->id) {
//Make the node with idInsert the first node
Node *new = (Node *)malloc(sizeof(Node)); //Allocate memory for the new node
//Add in data
new->id = idInsert;
new->next = list->head;
list->head = new;
} else { //Locate the node before the point of insertion
//Allocate memory for the node
Node *new = (Node *)malloc(sizeof(Node));
//Add in data
new->id = idInsert;
Node *current = list->head;
while (current->next != NULL && current->next->id < new->id) {
current = current->next;
}
new->next = current->next;
if (current->next != NULL) {
new->next->prev = new;
}
current->prev->next = new;
new->prev = current;
}
//Print this message if successful
printf("RECORD INSERTED: %d\n", idInsert);
}
static void *addRecord(List *list, int newID) {
//Allocate memory for the node
Node *new = (Node *)malloc(sizeof(Node));
//Add in data
new->id = newID;
new->prev = NULL;
//New node has no next, yet
new->next = NULL;
Node **next_p = &list->head;
while (*next_p) {
next_p = &(*next_p)->next;
}
*next_p = new;
list->last = new;
new->prev = *next_p;
return EXIT_SUCCESS;
}
static void printReverse(List *list) {
Node **tail = &list->last;
printf("LIST IN REVERSE ORDER:\n");
//Traversing until tail end of linked list
while (*tail) {
printf("Item ID: %d\n", (*tail)->id);
tail = &(*tail)->prev;
}
}
It seems like my addRecord method is working fine (this functions to add values to the end of the linked list), but my insert method is not working properly. When I execute the minimal reproducible code above, I am stuck in an infinite loop. My desired result after calling printReverse would be:
Item ID: 15
Item ID: 7
Item ID: 4
Item ID: 3
Item ID: 2
Item ID: 1
Could someone please point out what is going wrong in my insertion method?
Insert has three cases:
Insert at the start.
Insert at the middle.
Insert at the end.
Your weapon to sketch out your algorithm is a piece of a paper and a pencil, where you will draw what your code is doing.
Insert at the start
Your case for inserting at the start is not complete, since you need to set the new node's previous pointer to NULL, and the previous pointer of the node that was the old head should now be pointing to the newly created node.
That could be done like this:
Node *new = malloc(sizeof(Node)); //Allocate memory for the new node
list->head->prev = new;
new->prev = NULL;
// rest of your code
Insert at the end
Anyway, to answer your question, in your example, you could simply use the addRecord() method that appends a node in the list, when the node to be inserted goes to the end, like in your example, the node with id 15.
You can do it like this:
Node *current = list->head;
while (current->next != NULL && current->next->id < new->id) {
current = current->next;
}
// if the new node is the last one
if(current->next == NULL)
{
// append it to the list
addRecord(list, idInsert);
printf("RECORD INSERTED: %d\n", idInsert);
return;
}
assuming you are using the method addRecord() discussed in your previous question, and not the one you provide here.
But as #SomeProgrammerDude commented, you could simplify that by checking if the new node is greater than the last node, and if yes, you call the addRecord().
Insert at the middle
In the case of having only node with id 1 in the list, and you insert the node with id 15 at the end, this invokes Undefined Behavior:
current->prev->next = new;
since the current node (with id 1) has no previous node, thus it's set to NULL. So you are requesting for the next field in something not a structure or a union.. Same for having 1 and 15 already in the list, and trying to insert 5.
Try changing that to:
current->next = new;
However, with your code, you will request the id of list->head, even if the list is empty, meaning that head (and last) pointer is NULL. That will invoke Undefined Behavior (UB), which is likely to result in a segmentation fault.
For that reason, in the following code I will first check if the list is empty or if the new node shall be inserted at the end, since in both cases it is enough to just call the addRecord() method (which appends a node to the list).
The condition of the if statement is going to be this:
if (list->last == NULL || idInsert > list->last->id)
which, due to short circuiting is going to be evaluated in the following order:
If the last pointer is NULL, then for sure the condition will be evaluated to true since the operator is the logical OR, so a single true operand will suffice to determine what the overall outcome of the condition is going to be. That means, that it won't evaluate the second operand, so the last pointer will not be dereferenced (which would invoke UB, since we would be requesting the id of NULL).
Putting everything together:
#include <stdlib.h>
#include <stdio.h>
typedef struct NodeStruct Node;
//struct for each office item
struct NodeStruct {
int id;
struct NodeStruct *next;
struct NodeStruct *prev; //Create doubly linked list node
};
/** Structure for the whole list, including head and tail pointers. */
typedef struct {
/** Pointer to the first node on the list (or NULL ). */
Node *head;
Node *last;
} List;
List *list;
List *makeList();
void insert(int idInsert, List *list);
static void *addRecord(List *list, int newID);
static void printReverse(List *list);
int main(void) {
//Create an empty list for you to start.
list = (List *)makeList();
addRecord(list, 1);
addRecord(list, 2);
addRecord(list, 3);
addRecord(list, 4);
addRecord(list, 7);
insert(6, list);
insert(0, list);
insert(15, list);
printReverse(list);
}
List *makeList()
{
List *list = (List *) malloc( sizeof( List ) );
list->head = NULL;
list->last = NULL;
return list;
}
//Insert the record based on the ID if no duplicates exist
void insert(int idInsert, List *list)
{
// Insert at end, if list is empty or if id is greater than all existing ids
// Short circuting protects from derefercing a NULL pointer
if (list->last == NULL || idInsert > list->last->id) {
addRecord(list, idInsert);
} else if (idInsert < list->head->id) { // Insert at start
//Make the node with idInsert the first node
Node *new = malloc(sizeof(Node)); //Allocate memory for the new node
list->head->prev = new;
new->prev = NULL;
//Add in data
new->id = idInsert;
new->next = list->head;
list->head = new;
} else { // Insert in the middle
//Locate the node before the point of insertion
//Allocate memory for the node
Node *new = malloc(sizeof(Node));
//Add in data
new->id = idInsert;
Node *current = list->head;
while (current->next != NULL && current->next->id < new->id) {
current = current->next;
}
new->next = current->next;
if (current->next != NULL) {
new->next->prev = new;
}
current->next = new;
new->prev = current;
}
//Print this message if successful
printf("RECORD INSERTED: %d\n", idInsert);
}
static void *addRecord(List *list, int newID)
{
//Allocate memory for the node
Node *new = malloc(sizeof(Node));
//Add in data
new->id = newID;
new->prev = list->last;
new->next = NULL;
list->last = new;
// if list is empty
if(!list->head)
{
list->head = new;
return EXIT_SUCCESS;
}
Node **next_p = &list->head;
while (*next_p) {
next_p = &(*next_p)->next;
}
*next_p = new;
return EXIT_SUCCESS;
}
static void printReverse(List *list) {
Node **tail = &list->last;
printf("LIST IN REVERSE ORDER:\n");
//Traversing until tail end of linked list
while (*tail) {
printf("Item ID: %d\n", (*tail)->id);
tail = &(*tail)->prev;
}
}
Output:
RECORD INSERTED: 6
RECORD INSERTED: 0
RECORD INSERTED: 15
LIST IN REVERSE ORDER:
Item ID: 15
Item ID: 7
Item ID: 6
Item ID: 4
Item ID: 3
Item ID: 2
Item ID: 1
Item ID: 0
Appendix
Notice how I approach the special cases of insert at the start and end before tackling the middle case. That is because your list has head and last pointers, these special insertions can get done in constant time, O(1), since you don't have to scan (iterate over) the list.
However, in the middle insertion, you have to scan the list, in order to locate the appropriate index, and then insert the node at that index.
Remember: the operation of traversing a list can take linear time (traversing the whole list), which in asymptotic notation is O(n), where n is the size of the list.
PS: I also checked the next pointer, by using the print (in normal order) method discussed in the linked question.
PPS: When you are done, do not forget to free the list. I have a method for this in List (C), which is the same for a double linked list, except, that you also have to set the head and last pointers to NULL too.

Inserting a new node into a doubly linked list after a given node

This function inserts a new node after a given node in a doubly linked list.
It works well unless the list is empty or when given node is NULL.
I have tried to solve this problem by inserting the new node as head, but it doesn't add the new node or does problems when adding a second node.
void insert(Polynomial** node, int new_data, int pow) {
Polynomial* new_node = ( Polynomial*)malloc(sizeof( Polynomial));
new_node->num = new_data;
new_node->pow = pow;
if ((*node) == NULL) {
new_node->prev = NULL;
(*node) = new_node;
return;
}
new_node->next = (*node)->next;
(*node)->next = new_node;
new_node->prev = (*node);
if (new_node->next != NULL)
new_node->next->prev = new_node;
}
Struct:
typedef struct Polynomial {
int num;
int pow;
struct Polynomial* next;
struct Polynomial* prev;
}Polynomial;
When you create a new list, the first node's next pointer is unspecified. This could lead to undefined behaviour when inserting the second node, e.g. the 0xcdcdcdcd value you saw. Set it to null before returning:
if ((*node) == NULL) {
new_node->prev = new_node->next = NULL;
(*node) = new_node;
return;
}

Insert a number to a sorted linked list, why the number inserts to the second position every time?

I am working on a project about linked list, I have trouble with inserting a number to a sorted linked list. The number inserted to the second position every time, I cannot figure out where the problem is.Here is my code:
void insertSort(struct linkedList *n,int num,int *length){ //insert number to a sort linked list
node *new = (node *) malloc(sizeof(node)); //create a new node
new->next=NULL;
new->data = num;
while(n!=NULL&&n->data > new->data){ // find which position num should insert in sorted list
n = n->next;
}
new->next = n->next;
n->next= new;
length += 1;
}
n is head of the linked list. I initialized head points to the first node and has not value.
Here is how I call this function:
insertSort(head->next,num,&length);
The number inserted to the second position every time. Like I want to insert 45 into sorted linked list <16,32,72,81,97>, after inserting, the list would be <16,45,32,72,81,97>. 45 inserts to the second position for some reason.
The problem :
The number inserted to the second position every time...
is occurring because in this part of code:
while(n!=NULL&&n->data > new->data){ // find which position num should insert in sorted list
n = n->next;
}
new->next = n->next;
n->next= new;
you are inserting the new node after the n->next.
Assume the first node of your linked list is having data 16 and now you want to insert the new node with data 45 in the linked list, the while loop condition will fail as 16 > 45 will evaluate to false.
And the statement after while loop new->next = n->next; will set the next of new node to next of the first node and n->next= new; will insert the new node after first node. Hence, the new node inserted to second position every time.
There are few more problems with your function insertSort() like:
It does not track the head of the linked list while inserting a node to the linked list and,
What will happen if the node inserted is the first node of the linked list? In that case n will NULL and in insertSort() after while loop it is accessing next of n - new->next = n->next;.
Looking at the example you have given - <16,32,72,81,97>, you want to insert in ascending order.
You can do:
struct linkedList *insertSort(struct linkedList *n, int num, int *length) {
struct linkedList *first_node = n;
struct linkedList *new_node = malloc(sizeof(struct linkedList)); //create a new node
new_node->next=NULL;
new_node->data = num;
if (first_node == NULL || first_node->data >= new_node->data) {
new_node->next = first_node;
first_node = new_node;
} else {
struct linkedList *temp = first_node;
while (temp->next != NULL && temp->next->data < new_node->data) {
temp = temp->next;
}
new_node->next = temp->next;
temp->next = new_node;
}
*length += 1;
return first_node;
}
Here, you can see that I have changed return type void to struct linkedList * so that after inserting new node to appropriate location in linked list insertSort() will return the head of the linked list. That way you can keep track of head of linked list after every insertion. You just need to do:
head = insertSort(head, num, &length);
from wherever you are calling insertSort().
Alternatively, you can pass the address of head pointer in insertSort() and keep track of it, if you don't want to change the return type of insertSort(), like this:
void insertSort(struct linkedList **head, int num, int *length) {
struct linkedList *new_node = malloc(sizeof(struct linkedList)); //create a new node
new_node->next=NULL;
new_node->data = num;
if (*head == NULL || (*head)->data >= new_node->data) {
new_node->next = *head;
*head = new_node;
} else {
struct linkedList *temp = *head;
while (temp->next != NULL && temp->next->data < new_node->data) {
temp = temp->next;
}
new_node->next = temp->next;
temp->next = new_node;
}
*length += 1;
}
You can call insertSort() like this:
insertSort(&head, 32, &length);
Hope this helps.
because you are never testing the position of the node . your code only puts the new node at 2nd position . it does not checks where it should be in the sorted list
try below
void sortedInsert(struct Node** head_ref, struct Node* new_node) {
struct Node* current; /* Special case for the head end */
if(*head_ref == NULL || (*head_ref)->data >= new_node->data) {
new_node->next = *head_ref;
*head_ref = new_node;
}
else {
/*Locate the node before the point of insertion */
current =*head_ref;
while (current->next!=NULL && current->next->data < new_node->data)
{
current = current->next;
}
new_node->next =current->next;
current->next = new_node; }
}

inserting in singly linked list in ascending order

Say I have a singly linked list of elements in ascending order that looks like:
A->B->D->E
I want to insert C in between B and D.
I know how to point C to D, but I don't know how to point B to C since the linked list does not keep track of the prev node.
While you are scanning down the list of nodes you have to keep two pointers: one points to the current node that you are interested in, and the other points to the previous node.
A possible implementation follows:
struct node {
int value;
struct node *next;
};
void sorted_insert(struct node **head, struct node *element) {
// Is the linked list empty?
if (*head == NULL) {
element->next = NULL;
*head = element;
return;
}
// Should we insert at the head of the linked list
if (element->value < (*head)->value) {
element->next = *head;
*head = element;
return;
}
// Otherwise, find the last element that is smaller than this node
struct node *needle = *head;
while (true) {
if (needle->next == NULL)
break;
if (element->value < needle->next->value)
break;
needle = needle->next;
}
// Insert the element
element->next = needle->next;
needle->next = element;
return;
}
You don't need to point B to C, or to maintain a pointer to the previous element. One method is:
Step to node D
malloc() a new node
Copy the data and next member from node D to your new node
Copy the data for node C into the existing node D (which now becomes node C)
Point the next member of the old node D to the new node.
For instance, excluding the possibility of inserting at the head of the list:
void insert(struct node * head, const int data, const size_t before)
{
assert(before > 0);
struct node * node = head;
while ( before-- && node ) {
node = node->next;
}
if ( !node ) {
fprintf(stderr, "index out of range\n");
exit(EXIT_FAILURE);
}
struct node * new_node = malloc(sizeof *new_node);
if ( !new_node ) {
perror("couldn't allocate memory for node");
exit(EXIT_FAILURE);
}
new_node->data = node->data;
new_node->next = node->next;
node->next = new_node;
node->data = data;
}
Why not keep track of the 'previous' node as you iterate through the list? Please forgive any syntactic shortcomings, as I haven't compiled this, but this should give you the idea.
struct node {
char name[ 10 ];
struct node *next;
};
struct list {
struct node *head;
};
void insert_C(struct list *list) {
struct node *new_node = malloc(sizeof(struct node));
if( new_node == NULL ) {
/* Error handling */
}
strcpy(new_node->name, "C");
struct node *pnode;
struct node *prev_node = NULL;
for( pnode = list->head; pnode->next != null; pnode = pnode->next ) {
if( !strcmp(pnode->name, "D") ) {
if( prev_node == NULL ) {
/* The 'C' node is going to be the new head. */
new_node->next = list->head;
list->head = new_node;
}
else {
prev_node->next = new_node;
new_node->next = pnode;
}
break;
}
/* Remember this node for the next loop iteration! */
prev_node = pnode;
}
}

Resources