I have written a piece of code that uses linked lists. I get the user to enter a couple of numbers and then ask the user to enter the index of the digit he wishes to delete. I did some research and found out that i need to check whether the next node is the one I want to delete, then have 2 temp pointers point to the current node and the next node(which is the one i want to delete), then assign the next node of the first temp pointer to the next node of the second temp pointer then finally free the second temp pointer. Here is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int item;
struct node *next;
}ListNode;
void print(ListNode *head);
int deleteNode(ListNode **ptrHead, int index);
int main()
{
int n;
int remove;
ListNode *head = NULL;
ListNode *temp = NULL;
printf("Enter a value: ");
scanf("%d", &n);
while (n != -1)
{
if (head == NULL)
{
head = malloc(sizeof(ListNode));
temp = head;
}
else
{
temp->next = malloc(sizeof(ListNode));
temp = temp->next;
}
temp->item = n;
temp->next = NULL;
printf("Enter a value: ");
scanf("%d", &n);
}
printf("Enter index to remove: ");
scanf("%i", &remove);
while (remove != -1)
{
deleteNode(&head, remove);
print(head);
printf("Enter index to remove: ");
scanf("%i", &remove);
}
while (head != NULL)
{
temp = head;
head = head->next;
free(temp);
}
head = NULL;
return 0;
}
int deleteNode(ListNode **ptrHead, int index)
{
int count = 0;
ListNode* temp1 = NULL;
ListNode* temp2 = NULL;
while (count <= index)
{
if (index == 0)
{
temp2 = (*ptrHead)->next;
free((*ptrHead));
(*ptrHead) = temp2;
return 0;
break;
}
if (count+1 == index)//checking for the node ahead
{
temp1 = (*ptrHead);
temp2 = (*ptrHead)->next;//the one to free
temp1->next = temp2->next;
free(temp2);
return 0;
break;
}
(*ptrHead) = (*ptrHead)->next;
count++;
}
return -1;
}
void print(ListNode *head){
if (head == NULL)
{
return;
}
while (head != NULL)
{
printf("%i\n", head->item);
head = head->next;
}
}
So for example if i enter 1 2 3 4 5 -1, the linked list will contain 1 2 3 4 5. Then if i enter 0 for the index to remove, the program will print out 2 3 4 5. This works whether I enter 0 or 1. However, when I enter the indexes 2 and above, it gives me weird outputs like for example if I set the linked list as 1 2 3 4 5, and enter the index 2 to remove, by rights it should output 1 2 4 5, but instead it outputs 2 4 5, I have no idea whats going on, please point me in the right direction.
In deleteNode you use the actual headpointer to traverse the list. As you loop through the list you move the actual head! You should only modify (*ptrHead) when you delete the first element.
I suggest that you copy *ptrHead to a local variable and use the local variable to traverse the list.
I've highlighted the important lines with comments starting with // ***
int deleteNode(ListNode **ptrHead, int index)
{
int count = 0;
ListNode* temp1 = NULL;
ListNode* temp2 = NULL;
ListNode* traverse = *ptrHead; // *** make a copy that we can use to traverse the list
while (count <= index)
{
if (index == 0)
{
temp2 = (*ptrHead)->next;
free((*ptrHead));
(*ptrHead) = temp2; // *** Keep this line as it is to correctly handle deletion of index 0.
return 0;
break;
}
if (count+1 == index)//checking for the node ahead
{
temp1 = traverse; // *** Use local copy of pointer
temp2 = traverse->next;//the one to free // *** Use local copy of pointer
temp1->next = temp2->next;
free(temp2);
return 0;
break;
}
traverse = traverse->next; // *** Use local copy of pointer
count++;
}
return -1;
}
Find the modified deleteNode function (handles boundary conditions also , if we are trying to delete an index which is more then the list length)
int deleteNode(ListNode **ptrHead, int index)
{
int count = 0;
ListNode* temp1 = NULL;
ListNode* temp2 = NULL;
temp1 = (*ptrHead);
while((temp1 != NULL) && (count <= index))
{
if (index == 0)
{
temp2 = temp1->next;
free(temp1);
(*ptrHead) = temp2;
return 0;
}
if ((count+1 == index) && (temp1->next != NULL))
{
ListNode*temp = NULL;
temp = temp1->next;
temp2 = temp->next;
temp1->next = temp2;
free(temp);
return 0;
}
temp1 = temp1->next;
count++;
}
return -1;
}
Related
I am supposed to write a function to merge (put one at the end of another) two singly linked lists. The user inputs a series of numbers into the console, for example: 1 2 3 4 0 (0 signifies the end of input and is not an element of the list). These numbers are put into the linked list, the list now looks like this: 1 2 3 4. The process repeats again until we have two different linked lists. Then the merging function is called "void merge(struct Node head1, struct Node head2)". Programs ends after the new list is printed.
My thought process would be to first have my pointer point at the end of the first list, then just make a while loop that will go through the other list and make the next element of the first list the current element of the second list.
typedef struct Element Element;
struct Element
{
int data;
Element *next;
};
Element *addNew(int data)
{
Element *newN = (Element*)malloc(sizeof(Element));
newN->data = data;
newN->next = NULL;
return newN;
}
Element *add_on_beginning(Element *head, Element *newN)
{
newN->next = head;
return newN;
}
Element *add_on_end(Element *head, Element *newN)
{
if(head == NULL)
{
return newN;
}
Element *temp = head;
while(temp->next != NULL)
{
temp = temp->next;
}
temp->next = newN;
return head;
}
void printElement(Element *element)
{
printf("%d ", element->data);
}
void printList(Element *head)
{
Element *temp = head;
while(temp != NULL)
{
printElement(temp);
temp = temp->next;
}
}
void merge(Element *head1, Element *head2)
{
Element *temp1 = head1;
Element *temp2 = head2;
while(temp1->next != NULL)
{
temp1 = temp1->next;
}
while(temp2->next != NULL)
{
temp1->next = temp2;
temp2 = temp2->next;
}
}
int main()
{
Element *head1 = NULL;
Element *head2 = NULL;
int arr[1000];
char temp1;
char temp2;
int i = 0;
int j = 0;
printf("Input the first set of elements: \n");
while(temp1 != '\n')
{
scanf("%d%c", &arr[i], &temp1);
if(arr[i] == 0)
{
break;
}
head1 = add_on_end(head1, addNew(arr[i]));
i++;
}
printf("Input the second set of elements: \n");
while(temp2 != '\n')
{
scanf("%d%c", &arr[j], &temp2);
if(arr[j] == 0)
{
break;
}
head2 = add_on_end(head2, addNew(arr[j]));
j++;
}
merge(head1, head2);
printList(head1);
return 0;
}
So for some reason, the function only reads last two elements of the second list.
INPUT:
1 2 3 4 0
5 6 7 8 0
OUTPUT:
1 2 3 4 7 8
The result I'm supposed to get is
INPUT:
1 2 3 4 0
5 6 7 8 0
OUTPUT:
1 2 3 4 5 6 7 8
Think "code reuse".
You've already written the functionality you want. Reuse it...
printList( add_on_end( head1, head2 ) );
You've used malloc() to grab space for your nodes from the heap.
main() exits immediately, but it's good practice to at least acknowledge in a comment that you're not iteratively calling free().
Edit printList() could be shifted into main() and its "final traversal" of the linked list used to make those calls to free().
This function
void merge(Element *head1, Element *head2)
{
Element *temp1 = head1;
Element *temp2 = head2;
while(temp1->next != NULL)
{
temp1 = temp1->next;
}
while(temp2->next != NULL)
{
temp1->next = temp2;
temp2 = temp2->next;
}
}
is invalid.
First of all it does not change the original pointers head1 and head2 because they are passed to the function by value. So the function deals with copies of the original pointers.
Secondly in the function there is no check whether head1 or head2 is equal to NULL.
The function can be defined the following way
void merge( Element **head1, Element **head2 )
{
if ( *head1 == NULL )
{
*head1 = *head2;
*head2 = NULL;
}
else if ( *head2 != NULL )
{
while ( *head1 != NULL ) head1 = &( *head1 )->next;
for ( ; *head2 != NULL; head2 = &( *head2 )->next )
{
*head1 = *head2;
head1 = &( *head1 )->next;
}
}
}
Pay attention to that there is no need to declare an array to input data in the list.
Also these while loops
char temp1;
char temp2;
int i = 0;
int j = 0;
printf("Input the first set of elements: \n");
while(temp1 != '\n')
//..
and
while(temp2 != '\n')
//...
has undefined behavior because neither temp1 nor temp2 are initialized.
One of your problems is:
while(temp2->next != NULL) {
temp1->next = temp2;
temp2 = temp2->next;
}
You are not updating the value of temp1.
Also, why don't you just instead of this second while do:
temp1->next = temp2;
I mean linked list 2 is properly linked, you just need to link the end of the first list with the beginning of the second.
I am supposed to do an assignment in C programming language. It includes linked lists and reading user input from the console.
The user inputs numbers into the console, for example ( 1 3 5 7 0 ), which are added, one by one, to the beginning of the linked list. 0 marks the end of the transition. This is what the linked list should look like after the first part: 7 5 3 1
I need to code two different functions that will delete different elements of the linked list.
First function deletes all elements from the list that have the value that you input, and second function deletes the element on the position that the user inputs, if it exists.
At the end, you should print the list.
I've written the the first function correctly, and I am sure about it, with the second function (the one that deletes elements on a certain position) I had some trouble. I made a simple function that counts how many nodes are there in total, so if someone puts a number larger than the amount of nodes, a message would pop up. I also used that function to make a for loop and used it as a limit when searching for the element on a certain position, if that makes any sense. The program also won't print anything, I have no idea why.
typedef struct Element Element;
struct Element
{
int number;
Element *next;
};
Element *addnewN(int number)
{
Element *newN = (Element*)malloc(sizeof(Element));
newN->number = number;
newN->next = NULL;
return newN;
}
Element *add_on_beginning(Element *head, Element *newN)
{
newN->next = head;
return head;
}
Element* delete_value(Element* head, int value)
{
Element *before = NULL;
Element *temp = head;
Element *newNhead = head;
while(temp != NULL)
{
if(temp->number == value)
{
if(before == NULL)
{
newNhead = temp->next;
free(temp);
temp = newNhead;
}
else
{
before->next = temp->next;
free(temp);
temp = before->next;
}
}
else
{
before = temp;
temp = temp->next;
}
}
return newNhead;
}
int counter(Element *head)
{
int count = 0;
Element *temp = head;
while(temp != NULL)
{
count++;
temp = temp->next;
}
return count;
}
Element* delete_on_position(Element* head, int position)
{
int limit = counter(head);
Element *temp = head;
Element *newNhead = head;
Element *before = NULL;
if(position > limit)
{
printf("Error.\n");
}
for(int i = 0; i < limit; i++)
{
if(position == 0)
{
newNhead = temp->next;
free(temp);
temp = newNhead;
}
else if(position == i)
{
before->next = temp->next;
free(temp);
temp = before->next;
}
else
{
before = temp;
temp = temp->next;
}
}
return head;
}
void printElement(Element *element)
{
printf("%d ", element->number);
}
void printList(Element *head)
{
Element *temp = head;
while(temp != NULL)
{
printElement(temp);
temp = temp->next;
}
}
void menu()
{
printf("\t MENU \n");
printf("1. Delete all elements from the list that have the value that
you input.\n");
printf("2. Delete the element on the position, if it exists.\n");
printf("3. Print the list. \n");
printf("4. Exit \n");
}
int main()
{
Element *head = NULL;
int i = 0;
int arr[1000];
char temp;
int x;
int y;
printf("Input the numbers you want: \n");
while(temp != '\n')
{
scanf("%d%c", &arr[i], &temp);
if(arr[i] == 0)
{
break;
}
head = add_on_beginning(head, addnewN(arr[i]));
i++;
}
menu();
while(1)
{
scanf("%d", &x);
switch(x)
{
case 1:
{
scanf("%d", &y);
head = delete_value(head, y);
break;
}
case 2:
{
scanf("%d", &y);
head = delete_on_position(head, y);
break;
}
case 3:
{
printList(head);
break;
}
case 4:
{
return 0;
}
}
}
return 0;
}
What you are supposed to get would be for example:
Input: 2 4 5 8 5 0 (in one line), and in one line each:
2
2
1
5
3
Output: 2 8
When debugged, the code does not show any errors.
add_on_beginning is not returning the correct value. It should return the node that was added, since it's the new head of the list. Nothing else will work correctly because of that, because head will always be NULL.
Element *add_on_beginning(Element *head, Element *newN)
{
newN->next = head;
return newN;
}
I wrote a program to perform singly linked list operation insert at a particular position now there is no nodes at the moment , when I give the the input: 3 to the question enter the position to be inserted it shows runtime error
void insert_pos()
{
struct node * temp, *loc;
int item,pos,len;
printf("enter the position to be insertd :");
scanf("%d", &pos);
if (pos == 1)
{
insert_beg();
}
else
{
len = length();
if (start == NULL)
{
insert_beg();
}
else if (pos > len)
{
insert_end();
}
else
{
newnode = (struct node *)malloc(sizeof(struct node));
printf("enter the data :");
scanf("%d", &item);
newnode->data = item;
int i;
temp = start;
loc = temp->next;
for (i = 1; i < pos - 1; i++)
{
temp = temp->next;
loc = loc->next;
}
temp->next = newnode;
newnode->next = loc;
}
}
}
int length()
{
int k = 1;
struct node * temp;
while (temp->next != NULL)
{
temp = temp->next;
k++;
}
return k;
}
out put
1.insert # beg
2.insert # end
3.insert # perticular pos
4.display
5.exit
enter your option :3
enter the position to be inserted :3
now a window pops up saying debug error
pls help me with it
the problem was here the temp was Uninitialized
int length()
{
int k = 1;
struct node * temp;
while (temp->next != NULL)
{
temp = temp->next;
k++;
}
return k;
}
the fix was to assign temp = start;
corrected program
int length()
{
int k = 1;
struct node * temp;
temp=start; // start is a global variable
while (temp->next != NULL)
{
temp = temp->next;
k++;
}
return k;
}
thanks every one for the tips !!!
I am trying to write a function that inserts numbers(from the user)to nodes (1 number for each node) and then sorts them in an ascending way.
I wrote this function:
void insertnode(struct n_node *head)
{
struct n_node *temp = head;
int number;
printf("Please insert a number to the node\n");
scanf("%d", &number);
while (number != SENTRY)
{
while ((temp->next != NULL) && (temp->next->num < number))
{
temp = temp->next;
}
struct n_node *addNode = (struct n_node*)malloc(sizeof(struct n_node));
addNode->num = number;
if (temp->next == NULL && number < temp->num)
{
addNode->next = temp;
head = addNode;
}
else
{
addNode->next = temp->next;
temp->next = addNode;
}
temp = head;
scanf("%d", &number);
}
options();
}
It compiles but right after I insert the first number is stops, gives me a break message and points on this line:
while ((temp->next != NULL) && (temp->next->num < number))
nothing appears on the error list, any help is appreciated, Thanks!
In your algorithm, you are not testing the special cases in the correct order:
if the list is empty, head is NULL and the test temp->next != NULL invokes undefined behaviour.
if the number is smaller than the number in the first node, there is no need to try and iterate over the list, the node needs to be inserted at the head.
You should first allocate the new node and check the special cases with a single test:
struct n_node *addNode = malloc(sizeof(struct n_node));
addNode->num = number;
if (head == NULL || number < head->num) {
addNode->next = head;
head = addNode;
}
Otherwise, your iteration loop is correct and the node is to be inserted after temp when you reach the false condition:
while (temp->next != NULL && temp->next->num < number) {
temp = temp->next;
}
addNode->next = temp->next;
temp->next = addNode;
The loop becomes much simpler:
void insertnode(struct n_node **headp) {
struct n_node *head = *headp;
int number;
printf("Please insert a number to the node\n");
while (scanf("%d", &number) == 1 && number != SENTRY) {
struct n_node *addNode = malloc(sizeof(struct n_node));
if (addNode == NULL) {
printf("out of memory\n");
return;
}
addNode->num = number;
if (head == NULL || number < head->num) {
addNode->next = head;
*headp = head = addNode;
} else {
struct n_node *temp = head;
while (temp->next != NULL && temp->next->num < number) {
temp = temp->next;
}
addNode->next = temp->next;
temp->next = addNode;
}
}
options(); // head is not passed to the function?
}
Also note the change in API to allow the function to update the list head in the caller's scope, the change to stop scanning for numbers upon end of file or a non number input in addition to a magic number.
I'm busy with implementation of singly linked list and have 2 functions: insert_back and insert_after.
Here is the listing of them:
void insert_back(int data)
{
node *temp1;
temp1 = (node*)malloc(sizeof(node));
temp1 = head;
while (temp1->next != NULL) {
temp1 = temp1->next;
}
node *temp;
temp = (node*)malloc(sizeof(node));
temp->data = data;
temp->next = NULL;
temp1->next = temp;
}
void insert_after(int pos, int data)
{
node *temp1;
temp1 = (node*)malloc(sizeof(node));
temp1 = head;
for (int i = 1; i < pos; i++) {
temp1 = temp1->next;
if (temp1 == NULL) {
return;
}
}
node *temp;
temp = (node*)malloc(sizeof(node));
temp->data = data;
temp->next = temp1->next;
temp1->next = temp;
}
As you can see they are almost the same and for insert back I want to write insert_after(null, 10). I can solve it by adding if condition and choose one of the loops, but it's not my aim.
Is it possible somehow to use one while or for loops together for serial numbers and null?
Also I see that param int pos is int. Should I use 0 instead of null?
You unnecessarily allocate memory in the following lines.
temp1 = (node*)malloc(sizeof(node));
temp1 = head;
This allocated memory will leak as you overwrite the returned address in temp1. You just need temp1 to walk over the list, so there is also no need to allocate any node itself. temp1 can point to any node.
I've taken the liberty to kind of from scratch write a routine doing both things in one go. If pos < 0 it will add the element to the end of the list, otherwise it will add it after the pos-th element, where the first element corresponds with pos == 1. If pos == 0 the element is added at the start of the list.
Also a small main is added to test the routine. new_node has been added to test if memory is not exhausted.
#include <stdlib.h>
#include <stdio.h>
typedef struct node
{
struct node * next;
int data;
} node;
node * head = NULL;
node * new_node(void)
{
node * result = malloc(sizeof(*result));
if (result == NULL)
{
fprintf(stderr, "Out of memory.\n");
exit(10);
}
return result;
}
void insert_after(int pos, int data)
{
node *walk, * prev;
int i;
prev = NULL;
walk = head;
for (i = 0; walk != NULL && i != pos; i++)
{
prev = walk;
walk = walk->next;
}
if (i != pos && pos > 0)
{
fprintf(stderr, "Location not found.\n");
exit(9);
}
else
{
walk = new_node();
walk->data = data;
if (prev == NULL)
{
walk->next = head;
head = walk;
}
else
{
walk->next = prev->next;
prev->next = walk;
}
}
}
int main(void)
{
int i;
node * wlk;
for (i = 0; i < 10; i++)
{
insert_after(-1, i);
}
for (i = 0; i < 10; i++)
{
insert_after(3, i+10);
}
for (wlk = head; wlk != NULL; wlk = wlk->next)
{
printf("%d\n", wlk->data);
}
return 0;
}
Since you are testing for the end of the chain with insert_after(pos,...) anyway, you could go for:
void insert_after(int pos, int data)
{
node *temp1= head;
for (int i=1; i<pos; i++) {
if (temp1->next==NULL) {
if (pos==INT_MAX)
break; // pos of INT_MAX means insert at end
// so we continue with this last item and append
else
return; // pos higher than length of chain
}
temp1 = temp1->next;
}
...
}
Or slightly more compact:
void insert_after(int pos, int data)
{
node *temp1= head;
for (int i=1; i<pos && temp1->next!=NULL; i++) {
temp1 = temp1->next;
}
if (temp1->next==NULL && pos!=INT_MAX)
return; // pos higher than length of chain, except for
// INT_MAX (for that we just want to continue)
...
}
Then you could use
void insert_back(int data)
{
insert_after(INT_MAX, data);
}