Problem was to find the intersection of 2 sorted linked lists and store the common elements in the third list.
My approach was to make temporary pointers temp1 and temp2 initializing both to head1 (head of list 1) and head2 (head of list 2) respectively.And then traversing both lists and comparing elements and shifting temp1 and temp2 accordingly.The code works fine.
Test case:
First linked list=> 1->2->3->4->6
Second linked list be 2->4->6->8, then function should create and return a third list as 2->4->6.
But I am confused about what is the time complexity: O(m+n) or O(min(m,n))? (m,n are number of elements in list 1 and list 2).
My Code:
#include<stdio.h>
#include<stdlib.h>
/* Link list node */
struct Node
{
int data;
struct Node* next;
};
void append(struct Node** head_ref, int new_data)
{
/* 1. allocate node */
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
struct Node *last = *head_ref; /* used in step 5*/
/* 2. put in the data */
new_node->data = new_data;
/* 3. This new node is going to be the last node, so make next
of it as NULL*/
new_node->next = NULL;
/* 4. If the Linked List is empty, then make the new node as head */
if (*head_ref == NULL)
{
*head_ref = new_node;
return;
}
/* 5. Else traverse till the last node */
while (last->next != NULL)
last = last->next;
/* 6. Change the next of last node */
last->next = new_node;
return;
}
struct Node* sortedIntersect(struct Node* head1,struct Node*head2)
{
struct Node*head3=NULL;
struct Node*temp1=head1;
struct Node*temp2=head2;
while(temp1!=NULL&&temp2!=NULL)
{
if(temp1->data<temp2->data)
{if(temp1->next!=NULL)
temp1=temp1->next;
else
break;
}
else if(temp1->data>temp2->data)
{
if(temp2->next!=NULL)
temp2=temp2->next;
else{
break;
}
}
else
{
append(&head3,temp1->data);
temp1=temp1->next;
temp2=temp2->next;
}
}
return head3;
}
/* Function to insert a node at the beginging of the linked list */
void push(struct Node** head_ref, int new_data)
{
/* allocate node */
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
/* put in the data */
new_node->data = new_data;
/* link the old list off the new node */
new_node->next = (*head_ref);
/* move the head to point to the new node */
(*head_ref) = new_node;
}
/* Function to print nodes in a given linked list */
void printList(struct Node *node)
{
while (node != NULL)
{
printf("%d ", node->data);
node = node->next;
}
}
int main()
{
/* Start with the empty lists */
struct Node* a = NULL;
struct Node* b = NULL;
struct Node *intersect = NULL;
/* Let us create the first sorted linked list to test the functions
Created linked list will be 1->2->3->4->5->6 */
push(&a, 6);
push(&a, 5);
push(&a, 4);
push(&a, 3);
push(&a, 2);
push(&a, 1);
/* Let us create the second sorted linked list
Created linked list will be 2->4->6->8 */
push(&b, 8);
push(&b, 6);
push(&b, 4);
push(&b, 2);
/* Find the intersection two linked lists */
intersect = sortedIntersect(a, b);
printf("\n Linked list containing common items of a & b \n ");
printList(intersect);
return 0;
}
This is a problem that can be solved in O(m+n).
However, this solution is not O(m+n). Each element you add in the method intersectSorted is added with the method append, which traverses the whole current output list.
So the time complexity is O((m+n)log(min(m,n))
As in each iteration of while, at least one of the pointers go to the next, and the condition of while termination is none of the pointers reach to the end, the time complexity would be O(min(m,n)).
In worst case it will be O(m+n)
example: {1,3,5,7} {2,4,6,8}
in this case you traverse both the
list.
In average case it will be
O(min(m,n) + number of times you don't increment the smaller list)
example : {1,2,3,4,6} {2,4,6,8,9,10}
in this case you terminate
the loop once you reach the end of first lined list but in between you
increment the second list without increment the first list.
In best case it will be O(min(m,n))
example: {1,2,3} {1,2,3,4,}
in this case you will terminate
the loop after reaching end of the first list.
Related
I was looking over examples of dynamic memory allocation being used in c programs but I've noticed that many of them do not use free at the end. I was wondering if that's just an error on the programmer's part or if there are some instances in which you shouldn't free up pointers at the end. Here is an example I saw. If I am right and there should be a free where would be the appropriate place to put it? (https://www.geeksforgeeks.org/linked-list-set-2-inserting-a-node/)
// A complete working C program to demonstrate all insertion methods
// on Linked List
#include <stdio.h>
#include <stdlib.h>
// A linked list node
struct Node
{
int data;
struct Node *next;
};
/* Given a reference (pointer to pointer) to the head of a list and
an int, inserts a new node on the front of the list. */
void push(struct Node** head_ref, int new_data)
{
/* 1. allocate node */
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
/* 2. put in the data */
new_node->data = new_data;
/* 3. Make next of new node as head */
new_node->next = (*head_ref);
/* 4. move the head to point to the new node */
(*head_ref) = new_node;
}
/* Given a node prev_node, insert a new node after the given
prev_node */
void insertAfter(struct Node* prev_node, int new_data)
{
/*1. check if the given prev_node is NULL */
if (prev_node == NULL)
{
printf("the given previous node cannot be NULL");
return;
}
/* 2. allocate new node */
struct Node* new_node =(struct Node*) malloc(sizeof(struct Node));
/* 3. put in the data */
new_node->data = new_data;
/* 4. Make next of new node as next of prev_node */
new_node->next = prev_node->next;
/* 5. move the next of prev_node as new_node */
prev_node->next = new_node;
}
/* Given a reference (pointer to pointer) to the head
of a list and an int, appends a new node at the end */
void append(struct Node** head_ref, int new_data)
{
/* 1. allocate node */
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
struct Node *last = *head_ref; /* used in step 5*/
/* 2. put in the data */
new_node->data = new_data;
/* 3. This new node is going to be the last node, so make next of
it as NULL*/
new_node->next = NULL;
/* 4. If the Linked List is empty, then make the new node as head */
if (*head_ref == NULL)
{
*head_ref = new_node;
return;
}
/* 5. Else traverse till the last node */
while (last->next != NULL)
last = last->next;
/* 6. Change the next of last node */
last->next = new_node;
return;
}
// This function prints contents of linked list starting from head
void printList(struct Node *node)
{
while (node != NULL)
{
printf(" %d ", node->data);
node = node->next;
}
}
/* Driver program to test above functions*/
int main()
{
/* Start with the empty list */
struct Node* head = NULL;
// Insert 6. So linked list becomes 6->NULL
append(&head, 6);
// Insert 7 at the beginning. So linked list becomes 7->6->NULL
push(&head, 7);
// Insert 1 at the beginning. So linked list becomes 1->7->6->NULL
push(&head, 1);
// Insert 4 at the end. So linked list becomes 1->7->6->4->NULL
append(&head, 4);
// Insert 8, after 7. So linked list becomes 1->7->8->6->4->NULL
insertAfter(head->next, 8);
printf("\n Created Linked list is: ");
printList(head);
return 0;
}
At the end of the program all memory is freed anyway so at one level it makes no difference.
Having said that the sample linked list really should have a deleteList function as this is meant to be an example of 'how to do it right'. And that delete should be called at the end of main. Somebody cutting and pasting this code will leak all over the place.
Its also a good habit to get into, tidy up after yourself. If you ever use valgrind you will want it to give you a clean bill of health
There are no circumstances under which it is ever 'bad' to free up the memory you used at the end of the program.
This question already has answers here:
Using pointers to remove item from singly-linked list
(8 answers)
Closed 2 years ago.
I am checking the parity of the length of a singly linked list:
if it's odd, I have to delete the first node;
if it's even, I have to delete the last node.
I am able to figure out the parity but can't delete the relevant nodes.
Given that I also have to use the signature void sil(struct node **head), what should I change and add to my code?
// C program to check length
// of a given linklist
#include<stdio.h>
#include<stdlib.h>
// Defining structure
struct Node
{
int data;
struct Node* next;
};
// Function to check the length of linklist
int LinkedListLength(struct Node* head)
{
while (head && head->next)
{
head = head->next->next;
}
if (!head)
return 0;
return 1;
}
// Push function
void push(struct Node** head, int info)
{
// Allocating node
struct Node* node = (struct Node*) malloc(sizeof(struct Node));
// Info into node
node->data = info;
// Next of new node to head
node->next = (*head);
// head points to new node
(*head) = node;
}
// Driver function
int main(void)
{
struct Node* head = NULL;
// Adding elements to Linked List
push(&head, 4);
push(&head, 5);
push(&head, 7);
push(&head, 2);
push(&head, 9);
push(&head, 6);
push(&head, 1);
push(&head, 2);
push(&head, 0);
push(&head, 5);
push(&head, 5);
int check = LinkedListLength(head);
// Checking for length of
// linklist
if(check == 0)
{
printf("Even\n");
}
else
{
printf("Odd\n");
}
return 0;
}
typedef struct Node Node;
You can do that relatively easily with a simple function that takes the address of your list and the parity value as parameters, e.g.
/** delete 1st or last node from list given parity,
* parity odd, delete 1st node, otherwise delete last
*/
void del_first_last_node (Node **head, int parity)
{
Node **ppn = head; /* pointer to pointer */
Node *pn = *head; /* pointer to node */
if (parity & 1) { /* is parity odd delete first node */
*ppn = pn->next; /* set node at current address to next */
free (pn);
return;
}
for (; pn; ppn = &pn->next, pn = pn->next) { /* loop to end */
if (pn->next == NULL) { /* if next pointer NULL */
*ppn = pn->next; /* set node at current address to next */
free (pn);
break;
}
}
}
Above, parity is checked for odd, and if so, the first node is deleted (and properly freed). If the parity is even, you loop to the end of the list and delete the last node (again freeing the deleted node)
Iterating with both the address of the node and a pointer to node means there is no need to keep track of the prior node or any special cases. You are simply replacing the node at the current address with the next in the list. In the case of the first node, you just replace the node at the current head address with the next node (and since you also maintain a pointer to the node which is unchanged, you use that to free the original node) For the last node, you are just replacing its contents with NULL. See Linus on Understanding Pointers
the idea behind deleting a node is in general the same:
Create temp node that points to the node you want to delete in your structure.
If you want to delete the head, you can first point to the head with your temp node and then set your head to point to the item next to it. It should look something like this: node->head = node->head->next; and then of course free your temp pointer.
If you want to delete the tail, there are several cases to be covered. If you don't use a sentinel node , you have to traverse your list in a way that it will not destroy or corrupt the original one. The code for that should look like this:
int deleteTail(list_t* list){
int toReturn;
//declare a temp pointer to the head of your list
node_t* temp = list->head;
//here you found the last node and have it in a temp pointer.
while(temp->next != NULL) temp=temp->next;
//get the value you want to return
toReturn = temp->data;
//free the last element
free(temp);
return toReturn;
}
"I am checking if the singly linked list is odd or even. If it's odd I have to delete first node and if it's even I have to delete last node.
I did the part where I found it's odd or even. But I can't delete nodes. I'll be really happy if you can help.
Also I have to use this parameter " void sil(struct node **head) " What should I change and add to my code?"
#include<stdio.h>
#include<stdlib.h>
struct node{
int data;
struct node *next;
};
void push(struct node** head, int info) {
struct node *newN = (struct node *) malloc(sizeof(struct node));
newN->data = info;
newN->next = *head;
*head= newN;
}
void sil(struct node **head){
if (*head==NULL) return;
struct node *ptail=NULL;
struct node *tail=*head;
int i;
for (i=1; tail->next!=NULL; ptail=tail, i++, tail=tail->next);
if (i%2){
tail=*head;
*head=(*head)->next;
}else{
ptail->next=NULL;
}
free(tail);
}
int main(void){
struct node *head = NULL;
push(&head, 4);
push(&head, 5);
push(&head, 7);
push(&head, 2);
push(&head, 9);
push(&head, 6);
push(&head, 1);
push(&head, 2);
push(&head, 0);
push(&head, 5);
push(&head, 5);
sil(&head);
return 0;
}
Try it.
I must write a code for a lab and i don't understand how i can insert the nodes with which function.
struct list
{int value;
struct list * next;};
int main()........
the code says that we ask the user how many integers (N) he wants to insert to the list.. so easy printf, scanf
AND THEN ..It will ask for the numbers and list them in the order they are given.
I think that i need a for loop
but i know many function for inserting for example insertAfter, push etc, etc
I need you help! Thank you
The structure you have given represents a node. You first create a head of the list, then you need to read numbers one by one, create a node for each number and append it at the end of the list using append() function defined in the code given below.
Here is the full program you require (function codes taken from geeksforgeeks.org):
#include <stdio.h>
#include <stdlib.h>
// A linked list node
struct Node
{
int data;
struct Node *next;
};
/* Given a reference (pointer to pointer) to the head
of a list and an int, appends a new node at the end */
void append(struct Node** head_ref, int new_data)
{
/* 1. allocate node */
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
struct Node *last = *head_ref; /* used in step 5*/
/* 2. put in the data */
new_node->data = new_data;
/* 3. This new node is going to be the last node, so make next of
it as NULL*/
new_node->next = NULL;
/* 4. If the Linked List is empty, then make the new node as head */
if (*head_ref == NULL)
{
*head_ref = new_node;
return;
}
/* 5. Else traverse till the last node */
while (last->next != NULL)
last = last->next;
/* 6. Change the next of last node */
last->next = new_node;
return;
}
// This function prints contents of linked list starting from head
void printList(struct Node *node)
{
while (node != NULL)
{
printf(" %d ", node->data);
node = node->next;
}
}
int main()
{
/* Start with the empty list */
struct Node* head = NULL;
int n;
scanf("%d", &n);
for(int i=0; i<n; i++) {
int e;
scanf("%d", &e);
append(&head, e);
}
printList(head);
}
I have been recently working on circular linked list and the way the most of the people write code is as given below:
#include<stdio.h>
#include<stdlib.h>
/* structure for a node */
struct Node
{
int data;
struct Node *next;
};
/* Function to insert a node at the begining of a Circular
linked list */
void push(struct Node **head_ref, int data)
{
struct Node *ptr1 = (struct Node *)malloc(sizeof(struct Node));
struct Node *temp = *head_ref;
ptr1->data = data;
ptr1->next = *head_ref;
/* If linked list is not NULL then set the next of last node */
if (*head_ref != NULL)
{
while (temp->next != *head_ref)
temp = temp->next;
temp->next = ptr1;
}
else
ptr1->next = ptr1; /*For the first node */
*head_ref = ptr1;
}
/* Function to print nodes in a given Circular linked list */
void printList(struct Node *head)
{
struct Node *temp = head;
if (head != NULL)
{
do
{
printf("%d ", temp->data);
temp = temp->next;
}
while (temp != head);
}
}
/* Driver program to test above functions */
int main()
{
/* Initialize lists as empty */
struct Node *head = NULL;
/* Created linked list will be 11->2->56->12 */
push(&head, 12);
push(&head, 56);
push(&head, 2);
push(&head, 11);
printf("Contents of Circular Linked List\n ");
printList(head);
return 0;
}
However, there is one thing is never understand while inserting at the beginning of the circular linked list. If our last node always points to the first node which also is same as saying that the last node *next pointer has the same address as the the *first pointer has, then why for inserting the items after first node, we have to travel the whole list and update the *next pointer of the last node to point the newly added node at the beginning. Instead of while loop why can't we simply do like this:
Node *newadded
newadded->next = first->next
first = newadded
Because *first pointer has the address of the first node so if we update the *first pointer then the last pointer which already was pointing to the first pointer should also update itself.
Why to travel the whole list?
Since the list is circular, the last element of the list needs to point to the first element of the list. When inserting a new element into the beginning of the list, the first element of the list has changed to be a different element. To maintain circularity, you must find the last element and make it point to the new first element.
One way to make the operation more efficient is to maintain the tail of the circular linked list, rather than the head. Then insertion to the tail and to the head can both be done in constant time.
Demo
Write a function AlternatingSplit() that takes one list and divides up its nodes to make two smaller lists ‘a’ and ‘b’. The sublists should be made from alternating elements in the original list. So if the original list is 0->1->0->1->0->1 then one sublist should be 0->0->0 and the other should be 1->1->1.
More details about the problem - http://www.geeksforgeeks.org/alternating-split-of-a-given-singly-linked-list/
Now i made this code and it's running successfully
#include<stdio.h>
#include<stdlib.h>
struct node
{
int num;
node *next;
};
node *start1 = NULL, *start2 = NULL, *start3 = NULL;
void push()
{
node *temp = (node *)malloc(sizeof(node));
printf("Enter number = ");
scanf("%d", &temp->num);
temp -> next = start1;
start1 = temp;
}
void split()
{
while(start1 != NULL)
{
node *temp1 = (node *)malloc(sizeof(node));
temp1 ->num = start1 ->num;
temp1->next = start2;
start2 = temp1;
start1 = start1 -> next;
if(start1 != NULL)
{
node *temp2 = (node *)malloc(sizeof(node));
temp2 ->num = start1 ->num;
temp2->next = start3;
start3 = temp2;
start1 = start1 -> next;
}
}
}
int main()
{
int n;
scanf("%d", &n);
while(n--)
push();
split();
node *temp = start2;
while(temp != NULL)
{
printf("%d ", temp ->num);
temp = temp ->next;
}
printf("\n");
temp = start3;
while(temp != NULL)
{
printf("%d ", temp ->num);
temp = temp ->next;
}
return 0;
}
And the code provided with the question is -
/*Program to alternatively split a linked list into two halves */
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
/* Link list node */
struct node
{
int data;
struct node* next;
};
/* pull off the front node of the source and put it in dest */
void MoveNode(struct node** destRef, struct node** sourceRef) ;
/* Given the source list, split its nodes into two shorter lists.
If we number the elements 0, 1, 2, ... then all the even elements
should go in the first list, and all the odd elements in the second.
The elements in the new lists may be in any order. */
void AlternatingSplit(struct node* source, struct node** aRef, struct node** bRef)
{
/* split the nodes of source to these 'a' and 'b' lists */
struct node* a = NULL;
struct node* b = NULL;
struct node* current = source;
while (current != NULL)
{
MoveNode(&a, ¤t); /* Move a node to list 'a' */
if (current != NULL)
{
MoveNode(&b, ¤t); /* Move a node to list 'b' */
}
}
*aRef = a;
*bRef = b;
}
/* Take the node from the front of the source, and move it to the front of the dest.
It is an error to call this with the source list empty.
Before calling MoveNode():
source == {1, 2, 3}
dest == {1, 2, 3}
Affter calling MoveNode():
source == {2, 3}
dest == {1, 1, 2, 3}
*/
void MoveNode(struct node** destRef, struct node** sourceRef)
{
/* the front source node */
struct node* newNode = *sourceRef;
assert(newNode != NULL);
/* Advance the source pointer */
*sourceRef = newNode->next;
/* Link the old dest off the new node */
newNode->next = *destRef;
/* Move dest to point to the new node */
*destRef = newNode;
}
/* UTILITY FUNCTIONS */
/* Function to insert a node at the beginging of the linked list */
void push(struct node** head_ref, int new_data)
{
/* allocate node */
struct node* new_node = (struct node*) malloc(sizeof(struct node));
/* put in the data */
new_node->data = new_data;
/* link the old list off the new node */
new_node->next = (*head_ref);
/* move the head to point to the new node */
(*head_ref) = new_node;
}
/* Function to print nodes in a given linked list */
void printList(struct node *node)
{
while(node!=NULL)
{
printf("%d ", node->data);
node = node->next;
}
}
/* Drier program to test above functions*/
int main()
{
/* Start with the empty list */
struct node* head = NULL;
struct node* a = NULL;
struct node* b = NULL;
/* Let us create a sorted linked list to test the functions
Created linked list will be 0->1->2->3->4->5 */
push(&head, 5);
push(&head, 4);
push(&head, 3);
push(&head, 2);
push(&head, 1);
push(&head, 0);
printf("\n Original linked List: ");
printList(head);
/* Remove duplicates from linked list */
AlternatingSplit(head, &a, &b);
printf("\n Resultant Linked List 'a' ");
printList(a);
printf("\n Resultant Linked List 'b' ");
printList(b);
getchar();
return 0;
}
My query here is, which of these two codes are more efficient and more correct for this question, considering the time complexity, space complexity and every other factor?
And why?
A detailed explanation will be more helpful.
When you just split a linked list, you don't need any memory allocations, it's enough to just shuffle around pointers.
Your code does memory allocations when splitting, so it is rather inefficient that way, the model answer code is much better.
But worse, your code leaks memory. It loses the pointers to original list elements without freeing them. So your code is actually buggy, in a bad way.
To fix just the memory leak, which is an actual bug, you would need to change the two start1 = start1 -> next; lines to this:
node *tmp_next = start1->next;
free(start1);
start1 = tmp_next;
For other changes, the model answer is a good example, but most important things would be: Get rid of the extra malloc calls, and do the split by moving nodes, instead of allocating new node and copying data (and, after above bugfix, freeing the old node). And then get rid of the global variables, instead add parameters to the functions, like in the model answer.
Just another quick split, no new allocations, and keeping the original list reduced to odd elements, while forming the new lists for even ones, along with comment on each critical step
void split_in_evenodd(node *orig)
{
if(!orig)
return;
node *e, *cur, *e_hd;
e = orig->next; // point first even member
e_hd = e; // keep a head pointer to even list
if(!e) // covers the case of list with single element
return;
orig->next = e->next; // make orig skip the even node
cur = orig->next; // cur moves to next odd node
while(cur && cur->next) {
e->next = cur->next; // even pointing to next even node
e = e->next; // move even list forward
cur->next = e->next; // update odds next
cur = e->next;// move current forward (to next odd)
}
}
While solving this problem, I came up with this approach where I have created separate head nodes for both the splits and then with the help of count variable, all odd count linked list nodes are sent to split linked list 1 and all even count linked list nodes are sent to split linked list 2.
Hope it helps! This code is in C language.
#include <stdio.h>
#include <stdlib.h>
struct node *add_at_end(struct node *ptr,int item);
struct node{
int data;
struct node *next;
};
void main(){
struct node *head=malloc(sizeof(struct node));
head->data=1;
head->next=NULL;
// first node gets created
struct node *ptr=head;
//now we will add other nodes at the end
ptr=add_at_end(ptr,2);
ptr=add_at_end(ptr,3);
ptr=add_at_end(ptr,4);
ptr=add_at_end(ptr,5);
//the nodes get added to the linked list.Now let's print the data of all these nodes
ptr=head;
while(ptr!=NULL){
printf("%d ",ptr->data);
ptr=ptr->next;
}
printf("\n");
int count;
struct node *splitNode=malloc(sizeof(struct node));
struct node *forward=malloc(sizeof(struct node));
forward=head;
//now we will create the 1st split linked list
struct node *headll1=malloc(sizeof(struct node));
splitNode=forward;
forward=forward->next;
headll1->data=splitNode->data;
headll1->next=NULL;
struct node *ptr1=headll1;
count=1;
//now we will create the 2nd split linked list
struct node *headll2=malloc(sizeof(struct node));
splitNode=forward;
forward=forward->next;
headll2->data=splitNode->data;
headll2->next=NULL;
struct node *ptr2=headll2;
count++;
//head nodes of both the split linked lists is ready
while(forward!=NULL){
splitNode=forward;
forward=forward->next;
count+=1;
if(count%2==1){
ptr1->next=splitNode;
splitNode->next=NULL;
ptr1=ptr1->next;
}else{
ptr2->next=splitNode;
splitNode->next=NULL;
ptr2=ptr2->next;
}
}
//we have finished adding the nodes to linked list 1 and 2 alternatively based on count.
//now let's print both the linked lists.
ptr1=headll1;
while(ptr1!=NULL){
printf("%d ",ptr1->data);
ptr1=ptr1->next;
}
printf("\n");
ptr2=headll2;
while(ptr2!=NULL){
printf("%d ",ptr2->data);
ptr2=ptr2->next;
}
}
struct node *add_at_end(struct node *ptr,int item){
struct node *temp=malloc(sizeof(struct node));
temp->data=item;
ptr->next=temp;
temp->next=NULL;
return temp;
}