C Program - Removing duplicates from LinkedList - c

I am trying out on removing duplicates from a linkedlist. The user will insert one value and then, the program will check if the user's input and value in the linkedlist are the same. If it's similar, it will remove and leave only one in the linkedlist. For e.g. linkedlist=10 100. user=10. outcome=10 100 and not 10 10 100.
int insertSorted(LinkedList *ll, int item)
{
ListNode *cur = ll->head;
int size = ll->size;
int i;
for (i = 0; i <= size; i++)
{
if ((size - i) == 0 || item < cur->item)
{
insertNode(ll, i, item); // function to insert the value into Linkedlist
return i;
}
cur = cur->next;
}
ListNode *current = ll->head;
while (current->next != NULL)
{
if (current->item == current->next->item)
{
ListNode *nextNext = current->next->next;
free(current->next);
current->next = nextNext;
}
else
{
current = current->next; // only advance if no deletion
}
}
return -1;
}

When you insert the new node (the value 10 in your example), you then return i;, making the rest of the code, which I suppose checks for duplicates not to execute.

If you always return after you insert, you don't reach the code that deletes the duplicate. I think you need to break instead.
Also, where do you modify the size of the linked-list when you delete an element?
Should be reduced by 1 if I understand correctly.
In addition, since you clean duplicates after every insertion, you don't need the conditional advancement in the deleting loop

Related

Why is my linked list while loop not working? (C)

I am unsure why the code below does not execute up to the while loop. It only gives this output:enter image description here
The desired output of this program is that the largest node of the linked list is taken, multiplied by 0.8, and then printed as an output.
Code:
struct Process{
int burst_time;
struct Process* next;
};
int main()
{
int i;
struct Process* head = NULL, *temp = NULL;
struct Process* current = head; // Reset the pointer
int proc_count, time_quantum, total_time;
// BTmax
int max = 0;
printf("How many processes?: ");
scanf("%d",&proc_count);
for(i = 0; i < proc_count; i++)
{
temp = malloc(sizeof(struct Process));
printf("\nEnter burst time of process %d: ", i + 1);
scanf("%d", &temp -> burst_time);
temp->next=NULL;
if(head==NULL)
{
head=temp;
current=head;
}
else
{
current->next=temp;
current=temp;
}
}
current = head;
// BTmax * 0.8
while(current != NULL)
{
if (head -> burst_time > max)
{
max = head->burst_time;
}
head = head->next;
}
time_quantum = max * 0.8;
printf("\nTime Quantum is: %d", time_quantum);
Also, inside while loop you are iterating head variable but in condition you are checking current != NULL
From the way you wrote your while loop (iterating via head=head->next) you are apparently trying to do these two things at the same time:
Scan the list for its largest element
Remove/deallocate each element after it has been considered
Although head=head->next does remove each element from the list, it neglects to deallocate (causing memory to leak).
This loop correctly does both the scanning and the removal/deallocation:
while (head != NULL)
{
if (head->burst_time > max)
{
max = head->burst_time;
}
temp = head;
head = head->next;
free(temp);
}
(Notice that the while condition should be testing head, not testing current. Thus, there is no need to initialize current=head prior to the loop.)
You'll want to change the final while loop. You're checking to make sure current isnt NULL but you're iterating with head. If you still need access to the data, changing the final while loop to this should work :
while(current != NULL) {
if (current->burst_time > max) max = current->burst_time;
current = current->next;
}
Finally, maybe you already have in your actual program, but you need to free() any memory allocated with malloc()
So if you're done with the list at that point you can change the final while loop to :
while(head != NULL) {
if (head->burst_time > max) max = head->burst_time;
temp = head;
head = head->next;
free(temp);
}

Print linked list up to specific number in C

Suppose I have a linked list of unknown length. I would like to have a function to print out whole list if the length is less than 10, and if its length more than 10, then display only first 10 nodes.
However, because I'm comparing the pointer and integer to print out first 10 nodes, I'm getting the following error:
ordered comparison between pointer and integer ('NodeT *' (aka 'struct node *') and 'int')
for (current = list; current < 30; current = current->next)
If I change it to have a count and loop while count is less than 10, I'm getting a segmentation fault.
How can I display first 10 nodes if list is length is more than 10?
I have the following function:
void *printNodes(NodeT *list) {
int length = countNodes(list); // finds length of a linked list
int count = 0;
NodeT *current;
if (list == NULL) {
printf("Empty list.\n");
}
if (length < 10) {
// Display all if number of nodes is less than 10
for (current = list; current != NULL; current = current->next) {
printf("%s\n", current->data);
}
} else {
// Display first 10 if number of nodes more than 10
for (current = list; current < 10; current = current->next) {
printf("%s\n", current->data);
// for (current = list; count < 10; current = current->next) {
// printf("%s\n", current->data);
// count++;
}
}
return 0;
}
For starters the return type void * of the function printNodes
void *printNodes(NodeT *list) {
does not make a sense.
You should declare the function at least like
void printNodes( const NodeT *list) {
As the number of potentially outputted nodes is known there is no need to determine how many nodes there are in the list.
If the condition of this if statement
if (list == NULL) {
printf("Empty list.\n");
}
evaluates to the logical true the function shall return.
The condition of the for loop where a pointer is compared with an integer
for (current = list; current < 10; current = current->next) {
does not make a sense.
The function can be declared and defined the following way.
void printNodes( const NodeT *list )
{
size_t n = 10;
if ( list == NULL )
{
printf("Empty list.\n");
}
else
{
for ( ; list != NULL && n--; list = list->next )
{
printf( "%s\n", list->data );
}
}
}
Another approach is to declare one more parameter that will specify how many nodes of the list you want to output. For example
void printNodes( const NodeT *list, size_t n )
{
if ( list == NULL )
{
printf("Empty list.\n");
}
else
{
for ( ; list != NULL && n--; list = list->next )
{
printf( "%s\n", list->data );
}
}
}
Consider adapting your main for loop to serve as a counter:
void printNodes(NodeT *list) {
if (list == NULL) {
printf("Empty list.\n");
return; // Note no more useless "pointer" return
}
int limit = 10; // Could easily be an argument
NodeT *current = list;
for (int i = 0; current && i < limit; ++i, current = current->next) {
printf("%s\n", current->data);
}
}
The key here is you need to test that both the pointer is valid and the counter hasn't tripped.
In your adaptation you walked off the end of the chain without paying attention to your current pointer.
You can try the else part in this way:
for (current = list; count< 10; count++, current = current->next)
///your code
You can use a for loop as mentioned by tadman or a while loop like this
int counter = 0;
NodeT *current = list;
while (counter < 10 && current != NULL)
{
/* Do your stuff */
current = current->next;
counter += 1;
}
Instead of finding the length of the linked list as you did, which might make the time complexity of your function linear, you just need to check if the counter is at most ten and if the current node is not null.

c bubblesort a link list

trying to get a function to run that will bubble sort a link list from smallest to largest number. I don't want the data to be moved around in the link list instead have the pointers be pointing elsewhere in case each link needs to hold a lot of data.
In each link I have a INT arrivalTime field that will house a integer value. THis number determines where the link should be in the list.
My program seems to hang at the moment, I'd appreciate if anyone could fix it up, Thanks
bubble sort function
void bubbleSort(struct order *start)
{
int swapped, i;
processData *current = start;
processData *temp;
struct order *lptr = NULL;
/* Checking for empty list */
if (current == NULL)
printf("null \n");
do
{
swapped = 0;
current = start;
while (current->next != lptr)
{
if (current->arrivalTime > current->next->arrivalTime)
{
temp = current;
current = current->next;
current->next = temp;
swapped = 1;
}
current = current->next;
}
lptr = current;
}
while (swapped);
}
structure of link list
struct order
{
int name;
int arrivalTime;
int quanta;
struct order * next;
};
typedef struct order processData;
Swapping two adjacent items in a singly-linked-list requires that you change three next pointers.
If the order is A --> B --> C --> D and you swap B with C to get A --> C --> B --> D then
A->next needs to point to C instead of B
B->next needs to point to D instead of C
C->next needs to point to B instead of D
This is a very slow thing you're trying to do - see this paper on comparing ways to sort a linked list.
Currently, your algorithm will never terminate because in your while loop, you set lptr = current, but then test whether current->next == lptr. This will never return true unless one of your list members points to itself.
If you do have a definite use case to bubble sort the linked list, consider this: The purpose of a linked list is that you access it by working sequentially from the list head to the item you want. If your initial list head is not the smallest or the largest and you're only changing pointers, you need to keep track of where the head of the list is.
I did think of a way to do it loosely based on yours, see below. Sorry it's a bit messy - I'm not a C expert (hope the memory allocation is OK...) and I'm sure there are optimisations. In particular I'm sure there are better ways to pass the headOfList pointer back to the main algorithm. I've tested it for a number of 100 member lists of structs with some negative numbers. I've left the code to generate them with random arrival times in main() so you can just paste this in where your old code was and run it.
processData *bubbleSort(processData *start)
{
int swapped;
processData *current = start;
processData *lheadptr = start;
processData *previous = NULL;
processData *oldPrevButBigger;
processData *oldAfterThisPair;
/* Checking for empty list */
if (current == NULL)
{
printf("null \n");
return NULL;
}
do
{
swapped = 0;
current = lheadptr;
previous = NULL;
while (current->next) //Stop when current->next is null (i.e. end of list)
{
if (current->arrivalTime > current->next->arrivalTime)
{
oldPrevButBigger = current;
oldAfterThisPair = current->next->next;
current = current->next;
current->next = oldPrevButBigger;
current->next->next = oldAfterThisPair;
if (!previous)
{
//If no previous, this was the head of the list, so need to update
lheadptr = current;
}
else
{
// If there is a "previous", then we're not at head of list, so need
// to update that pointer too
previous->next = current;
}
swapped = 1;
}
previous = current;
current = current->next;
}
}
while (swapped);
return lheadptr;
}
int main()
{
srand(time(NULL));
int NUM = 100;
processData* pointToLast = NULL;
int i;
processData orders[NUM];
//Generate a list with random arrival times (last member of the list generated first
for (i = 0; i < NUM; i++ )
{
orders[i].name = i;
orders[i].arrivalTime = rand()-1000000000;
orders[i].quanta = 500;
orders[i].next = pointToLast;
pointToLast = &orders[i];
}
printf("List before\n");
printf("===========\n");
for (i=0; i < NUM; i++)
{
printf("%i;%i;%i\n", pointToLast->name, pointToLast->arrivalTime, pointToLast->quanta);
pointToLast = pointToLast->next;
}
processData* newListHead = bubbleSort(&orders[NUM-1]);
printf("List after\n");
printf("===========\n");
for (i=0; i < NUM; i++)
{
printf("%i;%i;%i\n", newListHead->name, newListHead->arrivalTime, newListHead->quanta);
newListHead = newListHead->next;
}
return 0;
}

Delete a node from a linked list [duplicate]

This question already has answers here:
Deleting a middle node from a single linked list when pointer to the previous node is not available
(24 answers)
Closed 8 years ago.
what i want to do is make a function that will get a list as an input and a number and will delete the node of that list that equals to that particular number. So if i have a linked list lets say:
struct num // list 1
{
char *val;
struct num *next;
};
and i have added 4 items to that list, i want to be able to delete the third item and get back the new list with now 3 items. Everything i have tried till now though wont work, i think because i am not linking the remaining items correctly after i delete one of them.
Since you insist here is what i have till now
struct num1 *temp;
temp = head;
struct num1* deletend(int del){
for ( int i = 0; i < listSize; i++)
{
if (i == del){
free(temp);
}
temp = temp->next;
}
return temp;
}
The following code solves the purpose :
typedef struct num numNode; // typedef to escape repeated struct num
numNode* delete_item(numNode* startNode, int position)
{
int pos = 0;
numNode* current = NULL;
numNode* prev = NULL;
if ((start == NULL) || (position == 0)) // if empty list or 0th item deletion, return the list as it is
return start;
else if (position == 1) // if delete first item,
{
current = start; // this node to be deleted
start = start->next; // Set start to the next item
free current;
current = NULL; // delete the node
return start;
}
else
{
prev = start; // this will mark the previous node
current = prev->next; // this will mark the current node
pos = 2; // position 0, 1 taken care of
}
while ((current != NULL))
{
if (pos == position)
{
prev->next = current->next;
free current;
current = NULL;
break;
}
pos++;
}
return start;
}
You need to keep the pointer to the previous member to the one deleted. Then replace the pointer in the previous to the deleted member with the pointer to the next member that was in the deleted member.

Splitting a linked list

Why are the split lists always empty in this program? (It is derived from the code on the Wikipedia page on Linked Lists.)
/*
Example program from wikipedia linked list article
Modified to find nth node and to split the list
*/
#include <stdio.h>
#include <stdlib.h>
typedef struct ns
{
int data;
struct ns *next; /* pointer to next element in list */
} node;
node *list_add(node **p, int i)
{
node *n = (node *)malloc(sizeof(node));
if (n == NULL)
return NULL;
n->next = *p; //* the previous element (*p) now becomes the "next" element */
*p = n; //* add new empty element to the front (head) of the list */
n->data = i;
return *p;
}
void list_print(node *n)
{
int i=0;
if (n == NULL)
{
printf("list is empty\n");
}
while (n != NULL)
{
printf("Value at node #%d = %d\n", i, n->data);
n = n->next;
i++;
}
}
node *list_nth(node *head, int index) {
node *current = head;
node *temp=NULL;
int count = 0; // the index of the node we're currently looking at
while (current != NULL) {
if (count == index)
temp = current;
count++;
current = current->next;
}
return temp;
}
/*
This function is to split a linked list:
Return a list with nodes starting from index 'int ind' and
step the index by 'int step' until the end of list.
*/
node *list_split(node *head, int ind, int step) {
node *current = head;
node *temp=NULL;
int count = ind; // the index of the node we're currently looking at
temp = list_nth(current, ind);
while (current != NULL) {
count = count+step;
temp->next = list_nth(head, count);
current = current->next;
}
return temp; /* return the final stepped list */
}
int main(void)
{
node *n = NULL, *list1=NULL, *list2=NULL, *list3=NULL, *list4=NULL;
int i;
/* List with 30 nodes */
for(i=0;i<=30;i++){
list_add(&n, i);
}
list_print(n);
/* Get 1th, 5th, 9th, 13th, 18th ... nodes of n etc */
list1 = list_split(n, 1, 4);
list_print(list1);
list2 = list_split(n, 2, 4); /* 2, 6, 10, 14 etc */
list_print(list2);
list3 = list_split(n, 3, 4); /* 3, 7, 11, 15 etc */
list_print(list3);
list3 = list_split(n, 4, 4); /* 4, 8, 12, 16 etc */
list_print(list4);
getch();
return 0;
}
temp = list_nth(current, ind);
while (current != NULL) {
count = count+step;
temp->next = list_nth(head, count);
current = current->next;
}
You are finding the correct item to begin the split at, but look at what happens to temp from then on ... you only ever assign to temp->next.
You need to keep track of both the head of your split list and the tail where you are inserting new items.
The program, actually, has more than one problem.
Indexes are not a native way to address linked list content. Normally, pointers to nodes or iterators (which are disguised pointers to nodes) are used. With indexes, accessing a node has linear complexity (O(n)) instead of constant O(1).
Note that list_nth returns a pointer to a "live" node within a list, not a copy. By assigning to temp->next in list_split, you are rewiring the original list instead of creating a new one (but maybe it's intentional?)
Within list_split, temp is never advanced, so the loop just keeps attaching nodes to the head instead of to the tail.
Due to use of list_nth for finding nodes by iterating through the whole list from the beginning, list_split has quadratic time (O(n**2)) instead of linear time. It's better to rewrite the function to iterate through the list once and copy (or re-attach) required nodes as it passes them, instead of calling list_nth. Or, you can write current = list_nth(current, step).
[EDIT] Forgot to mention. Since you are rewiring the original list, writing list_nth(head, count) is incorrect: it will be travelling the "short-cirquited" list, not the unmodified one.
I also notice that it looks like you are skipping the first record in the list when you are calculating list_nth. Remember is C we normally start counting at zero.
Draw out a Linked List diagram and follow your logic:
[0]->[1]->[2]->[3]->[4]->[5]->[6]->[7]->[8]->[9]->...->[10]->[NULL]
Your description of what list_split is supposed to return is pretty clear, but it's not clear what is supposed to happen, if anything, to the original list. Assuming it's not supposed to change:
node *list_split(node *head, int ind, int step) {
node *current = head;
node *newlist=NULL;
node **end = &newlist;
node *temp = list_nth(current, ind);
while (temp != NULL) {
*end = (node *)malloc(sizeof(node));
if (*end == NULL) return NULL;
(*end)->data = temp->data;
end = &((*end)->next);
temp = list_nth(temp, step);
}
return newlist; /* return the final stepped list */
}
(You probably want to factor a list_insert routine out of that that inserts a new
node at a given location. list_add isn't very useful since it always adds to the
beginning of the list.)

Resources