Find value occurrences and delete nodes in linked list - c

I really need help with a problem about linked lists in C.
I need to create a function where I have to read the nodes in the list and, for each node, I have to find occurrences. If the occurrences of the value are equals or greater than a variable value, this nodes must be deleted.
Example:
1->3->8->5->6->8->3->8->9
#of occurrences >= 3
So all the nodes with value 8 must be deleted.
Modified list:
1->3->5->6->3->9
Thank you so much.
Oh sorry my bad.
Yes I tried some solutions, but still didn't find one that works.
For delete all occurrences of a value I did this:
void deleteOccurrences(List *head, int val){
Lista *temp = *testa, *prev;
while(temp != NULL && temp->val == val){
*head = temp->next;
free(temp);
temp = *head;
}
while(temp != NULL){
while (temp != NULL && temp->val != val){
prev = temp;
temp = temp->next;
}
if(temp == NULL)
return;
prev->next = temp->next;
free(temp);
temp = prev->next;
}
}
and for count occurrences I did:
bool countOccurrences(List head, int val, int occur){
int count = 0;
while(head != NULL){
if(head->val == val)
count++;
head = testa->next;
}
if(count >= occur)
return true;
return false;
}
Then the function I'm trying to using is something like this:
void manageList(List head){
while(head != NULL){
int val = head->val;
if(countOccurences(head, val, 3))
deleteOccurrences(&head, val);
head = head->next;
}
}
This is the main:
int main(){
List head;
head = NULL;
head = insert(head,9);
head = insert(head,8);
head = insert(head,3);
head = insert(head,8);
head = insert(head,6);
head = insert(head,5);
head = insert(head,8);
head = insert(head,3);
head = insert(head,1);
manageList(head);
return 0;
}
where insert() function is just an insert at the beginning of the list.
This is the definition of the node:
typedef struct El{
int val;
struct El *next;
}ElemList;
typedef ElemList *List;
When I compile and run this I get a segmentation fault error.
If I try to run just the deleteOccurrences() function or the countOccurrences() function, they work as expected.
The problem is in this function manageList() that I don't understand how to read the list and in the same time find the occurrences and delete nodes.

void manageList(List *head){
ElemList *cur = *head;
while(cur != NULL){
int val = cur->val;
if(countOccurences(cur, val, 3)){
deleteOccurrences(cur, val);
cur = *head;
}else
head = head->next;
}
}

Related

C programming - Reverse a linked link by iterative method

I am trying to reverse a linked by iterative method. Magically, after watching tutorial and trying to recode myself, the program works successfully. However, when I review the code, I hit a question: in line 23, why we must use temp1->next instead of temp1? When traversing to the end of the linked list, which case we use the condition (the node != NULL)? In which case we use (the link of the node ! = NULL)? I fully appreciate it if anyone can enlighten me.
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node* next;
};
struct Node* Insert(struct Node* head, int data)
{
struct Node* temp = (struct Node*) malloc(sizeof(struct Node));
temp->data = data;
temp->next = NULL;
//If the list is empty
if (head == NULL)
{
head = temp;
}
else //The list is not empty
{
struct Node* temp1 = head;
while (temp1->next != NULL)
{
temp1 = temp1->next;
}
temp1->next = temp;
}
return head;
}
void Print(struct Node* head)
{
struct Node* temp = head;
while (temp != NULL)
{
printf("%d ", temp->data);
temp = temp->next;
}
printf("\n");
}
struct Node* Reverse(struct Node* head)
{
struct Node* *prev, *current, *next;
current = head;
prev = NULL;
while (current != NULL)
{
next = current->next;
current->next = prev;
prev = current;
current = next;
}
head = prev;
return head;
}
int main()
{
struct Node* head = NULL;
printf("Enter the length of the linked list you want to create: ");
int length;
scanf("%d", &length);
printf("Enter the value you want to input: ");
int i;
for (i = 0; i < length; i++)
{
int x;
scanf("%d", &x);
head = Insert(head, x);
}
printf("Given linked list\n");
Print(head);
head = Reverse(head);
printf("\nReversed linked list \n");
Print(head);
return 0;
}
In that case, inside the while condition, on line 23, you can notice that the program is using temp1 = temp1->next, if you change the condition to temp1 != NULL when it reaches the last element of linked list it'll collect trash from memory or even result in an error, because NULL don't have a next position.
So, you use temp1 != NULL if you are accessing the data inside the list and temp1->next != NULL if you are manipulating the next positions of the linked list.
Because temp1->next at the end of the linked list is NULL, however, the last node has data, if you use temp1 == NULL you would say that the last node is NULL, which is not the case. So you want to end the loop when the "pointer to the next node" is NULL, not when the next node is NULL.

Removing node from doubly linked list gives segmentation fault - C

I have written a program that can can add char characters to the start of a doubly linked list. Now once I have this list, the aim of my program is to remove certain char character(s) from the list entirely. For example (using curly brackets only for representative purposes): if list consists of { a, b, b, a, c }, then my program can remove all "b" from the list to make it { a, a, c}. Moreover, if my list is {b, a, c, a} or {a, c, a, b} and if I want to remove "b" then the program works fine for both cases and gives me {a, c, a}.
But there's a number of issues (for all cases assume I want to remove "b"):
if my list is {b, a, b, a, c} ("b" at front and somewhere in middle), I get segmentation fault (I think it has to do with using cursor in the while loop, but I don't know why exactly and how to fix it)
if my list is {a, b, b, a, c, b} ("b" in middle and at last) then output gives me weird symbols (I'm assuming its a memory fault, don't know why)
Here is the code I am using:
#include<stdio.h>
#include<stdlib.h>
struct list
{
int data;
struct list* next;
struct list* prev;
};
struct list* head; // global variable - pointer to head node of list.
struct list* last; // global variable - pointer to last node of list
//Creates a new list and returns pointer to it.
struct list* GetNewNode(char x)
{
struct list* newNode
= malloc(sizeof(struct list));
newNode->data = x;
newNode->prev = NULL;
newNode->next = NULL;
return newNode;
}
//Inserts a list at head of doubly linked list
void InsertAtHead(char x)
{
struct list* newNode = GetNewNode(x);
if(head == NULL)
{
head = newNode;
return;
}
head->prev = newNode;
newNode->next = head;
head = newNode;
struct list* temp = head;
while (temp->next != NULL) temp = temp->next;
last = temp;
}
void remove_element (char character)
{
struct list * cursor, *previous, *store_el;
//int boolean = 0;
if (head == NULL) return;
else
{
cursor = head;
while(cursor != NULL)
{
if (cursor->data == character)
{
if (cursor->prev == NULL)
{
// printf("deleting from front\n");
previous = head;
head = head->next;
head->prev = NULL;
//boolean = 1;
//free(previous);
}
if (cursor->next == NULL)
{
//printf("deleting from back\n");
previous = last;
last = last->prev;
last->next = NULL;
//boolean = 1;
//free(previous);
}
else
{
// printf("deleting from middle\n");
previous = cursor;
cursor = cursor->next;
cursor->prev = previous->prev;
store_el = previous->prev;
store_el->next = cursor;
cursor = head;
}
free(previous);
//printf("head data = %c\n", cursor->data);
}
cursor = cursor->next;
}
}
}
//Prints all the elements in linked list in forward traversal order
void Print()
{
struct list* temp = head;
printf("Forward: ");
while(temp != NULL)
{
printf("%c ",temp->data);
temp = temp->next;
}
printf("\n");
}
int main()
{
char character;
/*Driver code to test the implementation*/
head = NULL; // empty list. set head as NULL.
// Calling an Insert and printing list before and after deletion of character
InsertAtHead('c');
InsertAtHead('a');
InsertAtHead('b');
InsertAtHead('b');
InsertAtHead('a');
Print();
printf("After deletion:\n");
remove_element ('b');
Print();
}
/*
*I changed the name of your variable 'last' to 'tail'
*I removed the code at the end of your InsertAtHead function
*I added "tail = newNode;"
*I changed the name of your variable 'previous' to 'garbage'
*I removed your variable 'store_el' completely.
*I could have changed the whole code in your remove element function because the 3 cases are unnecessary but anyway.
*/
//Inserts a list at head of doubly linked list
void InsertAtHead(char x){
struct list* newNode = GetNewNode(x);
if (head == NULL){
head = newNode;
tail = newNode;
return;
}
head->prev = newNode;
newNode->next = head;
head = newNode;
}
void remove_element (char character){
struct list * cursor, *garbage;
cursor = head;
while(cursor != NULL){
if (cursor->data == character){
garbage = cursor;
if (cursor->prev == NULL){
head = head->next;
If (head!=NULL) head->prev = NULL;
cursor=head;
}else if (cursor->next == NULL){
tail = tail->prev;
tail->next = NULL;
cursor=NULL;
}else{
garbage->prev->next = garbage->next;
garbage->next->prev = garbage->prev;
cursor=cursor->next;
}
free(garbage);
} else cursor=cursor->next;
}
}
Try it now.
The problem with your code was that you were using the memory you freed.
/*
*cursor and previous point to the same memory address
*you free the memory that the variable previous points so the cursor points to that freed memory
*when you save the next address to the cursor using that freed memory you create an undefined behaviour (your code may work or may not)
*/
cursor = head;
while(cursor != NULL)
{
if (cursor->data == character)
{
if (cursor->prev == NULL)
{
previous = head;
head = head->next;
head->prev = NULL;
free(previous);
...
cursor=cursor->next;
The Improved Code:
#include<stdio.h>
#include<stdlib.h>
//The type of your variable data was wrong. I changed it to char
struct list{
char data;
struct list *prev, *next
};
void remove_element (char character){
struct list * cursor, *garbage;
cursor = head;
while(cursor != NULL){
if (cursor->data == character){
garbage = cursor;
if (garbage->prev!=NULL ) garbage->prev->next = garbage->next;
if (garbage->next!=NULL ) garbage->next->prev = garbage->prev;
cursor=cursor->next;
if (head==garbage) head=cursor;
//Basically the tail variable has no use for your current program.
//if (tail==garbage) tail=garbage->prev;
free(garbage);
} else cursor=cursor->next;
}
}
Try to update the cursor
cursor = head;
after you delete from the front.
Ellothere I think the problem in your program is you are assigning the address of the node in previous but you are not freeing it side by side.
if (cursor->prev == NULL)
{
// printf("deleting from front\n");
previous = head;
head = head->next;
head->prev = NULL;
//boolean = 1;
//free(previous);
}
if (cursor->next == NULL)
{
//printf("deleting from back\n");
previous = last;
last = last->prev;
last->next = NULL;
//boolean = 1;
//free(previous);
}
Here you are storing node but freeing it at the end and then there are 2 if statements here then what is happening is both 'b' in {a b b a c} are next to each other so first previous variable is storing the address of first 'b' then it is storing the address of next 'b' and it is just freeing that 'b' and that one 'b' remains there . In short you should free the node side- by - side. I did this small change and it works fine .
if (cursor->prev == NULL)
{
// printf("deleting from front\n");
previous = head;
head = head->next;
head->prev = NULL;
free(previous);
//boolean = 1;
//free(previous);
}
if (cursor->next == NULL)
{
//printf("deleting from back\n");
previous = last;
last = last->prev;
last->next = NULL;
free(previous);
//boolean = 1;
//free(previous);
}
else
{
// printf("deleting from middle\n");
previous = cursor;
cursor = cursor->next;
cursor->prev = previous->prev;
store_el = previous->prev;
store_el->next = cursor;
cursor = head;
}
I have just added a free function in both if statements.

In my Singly linked List implementation why is it even though I allocated memory for the node to be freed, the pointer to the Node isn't NULL?

Using the delete_SLL function I want to delete the head of this singly linked list(head = 4). Although I get the correct output, the var struct Node* "temp" holding the value of the head isn't NULL. What is it about the variable "temp" that the free function not like? Is the node temp not Malloc-ed when setting it equal to the list head?
Source:Deleting a Node
Code:
#include <stdio.h>
#include <stdlib.h>
struct Node{
int item;
struct Node* next;
};
struct List{
struct Node* head;
struct Node* tail;
};
int SLL_empty(struct List* lst){
return lst->head == NULL ;
}
//newLst work
struct List newLst(){
struct List lst;
lst.head = NULL;
lst.tail = NULL;
return lst;
}
//Inserts a node to the front of the list[WORKS]
void insert_SLL(struct List* lst, int x){
struct Node* nde = (struct Node*)malloc(sizeof(struct Node));
nde->next = lst->head;
nde->item = x;
if (SLL_empty(lst))
lst->tail=nde;
lst->head = nde;
}
//Deletes a given Node
void delete_SLL(struct List* lst, int x){
struct Node* temp = (struct Node*)malloc(sizeof(struct Node));;
temp = lst->head;
struct Node* prev = NULL;`enter code here`
//If the head has the key
if (temp != NULL && temp->item == x){
lst->head = temp->next;
temp->next = NULL;
free(temp);
}
// stops once the key is found
while(temp != NULL && temp->item != x){
prev = temp;
temp= temp->next;
}
//If not in list
if (temp == NULL) return;
//If middle
if (temp != NULL && temp->item == x){
prev->next = temp->next;
temp->next = NULL;
}
//if at the end
if (temp != NULL && temp->item == lst->tail->item){
lst->tail= prev;
prev->next = NULL;
}
free(temp);
}
int SLL_pop(struct List *list){
struct Node* nde = list->head;
int item = nde->item;
list->head = nde->next;
free(nde);
if (SLL_empty(list))
list->tail = NULL;
return item;
}
int main(int argc, const char * argv[]) {
int i;
struct List list = newLst();
for (i = 0; i < 5; ++i)
insert_SLL(&list, i);
// printf("The length of the linkedLst is: %d\n",SLL_length(&list));
delete_SLL(&list, 4);
while ( list.head != NULL )
printf("Node: %d\n", SLL_pop(&list));
return 0;
}
The main purpose of free() is to ask the OS take the allocated memory back to the system. You might not be able to "see" that but if you try to access any element at the "temp" afterward, you should get an error.
While the "temp" in the program is only a variable. C doesn't require to, and can't change the given pointer to NULL due to pass-by-value sense. It's the programmer's work to remember that this pointer is no longer valid.
Or you can set it to NULL manually each time you free a pointer.

Why position 0 in delete node does not work?

Im new to c programming. I wanted to create a linked list from a given file and then randomly get a node from linked list then delete that node.
So the code works great but for the position 0 in linked list does not work.
Please help me
here's the code:
typedef struct node{
int *name;
struct node *next;
}node;
delete node:
void deleteNode(node **head_ref, int position){
if(*head_ref == NULL){
return;
}
node * temp = *head_ref;
if(position == 0)
{
*head_ref = (*head_ref)->next;
return;
}
int h;
for(h=0 ; temp!=NULL && h<position-1 ; h++){
temp = temp->next;
}
if(temp == NULL || temp->next == NULL)
return;
node * next = temp->next->next;
free(temp->next);
temp->next = next;}
getting random node:
void RandomFromList(node *head){
// IF list is empty
if (head == NULL){
return -1;
}
word = head->name;
// Iterate from the (k+1)th element to nth element
node *current = head;
int n;
for (n=2; current!=NULL; n++)
{
// change result with probability 1/n
if (rand() % n == 0)
word = current->name;
// Move to next node
current = current->next;
}
sprintf(words , "%s" , word);
deleteNode(&head , search(head , word));
printf("Randomly selected key is %s\n", words);}
and the file Reader:
node* fileReader(FILE *file){
node *t = malloc(sizeof(node));
char TopicName[20];
int fileRead = fscanf(file,"%s",TopicName);
if(fileRead != EOF){
t->name = strdup(TopicName);
tedad++;
t->next = fileReader(file);
}
if(fileRead == EOF) {
return NULL;
}
return t;}
EDIT:
When the code run's and when the position randomly got 0 the 0 position of linked list doesn't delete and continues with that node in linked list.
EDIT2:I changed my delete node and it works well without any problem, thank you guys!
node* deleteNode(node* head, unsigned i){
node* next;
if(head == NULL)
return head;
next = head->next;
return i == 0
? (free(head), next)
: (head->next = delete_at_index(next, i - 1), head);
}
The major logical problem I see with your delete function is that it is void, i.e. it returns nothing. This is fine if the node being deleted is in the middle (or end) of the list, because the head does not change. But for the case of deleting the head, the caller might expect that his reference would then point to the next node (or null, if a list of one element) after making the call. Consider this code:
node* deleteNode (node *head_ref, int position)
{
// passing in a NULL list returns NULL
if (head_ref == NULL) {
{
return NULL;
}
// deleting the first element returns the second element as the new head
node* temp = head_ref;
if (position == 0)
{
node* ret = temp->next;
free(head_ref);
return ret;
}
// otherwise walk down the list to one before the deletion position
for (int h=0; temp != NULL && h < position-1; h++) {
temp = temp->next;
}
// if found, delete the node at the desired position
if (temp != NULL && temp->next == NULL) {
node* next = temp->next->next;
free(temp->next);
temp->next = next;
}
// for cases other than deleting the head, just return the current
// (unmodified) head
return head_ref;
}
This isn't related to your problem, but don't forget to free the memory:
node * temp = *head_ref;
if(position == 0)
{
*head_ref = temp->next;
free(temp); // <--------
return;
}
Also, you already have a pointer (temp) to *head_ref, it looks cleaner to me to just use that pointer instead of dereferencing head_ref again.
void deleteNode(node **head_ref, int pos){
node *del;
for ( ; *head_ref; head_ref = &(*head_ref)->next) {
if (pos-- <= 0) break;
}
if (!*head_ref) return; // Reached end of list: nothing found
del = *head_ref;
*head_ref = del->next;
free(del);
return;
}
If you want to keep deleteNode void, then the problem is with your RandomFromList function. You are just changing the * head that exists in the function body not the pointer you passed to the function, so it's still pointing to the previous node.
It's because that pointers are passed by value (copied) like other things in C.
Try making RandomFromList return the head pointer.
P.s. I think you also have some memory leaks in the delete function.

Malloc with scope and global variables

#include<stdio.h>
#include<stdlib.h>
struct node {
int num;
struct node *next;
}*head=NULL, *curr=NULL;
void print(){
curr = head;
while(curr != NULL){
printf("%d\n", curr->num);
curr = curr->next;
}
}
struct node* memAlo(){
return (struct node *)malloc(sizeof(struct node));
}
void addNode(int no){
curr = head;
while(curr != NULL){
curr = curr->next;
}
curr = memAlo();
if(curr == NULL){
printf("\nmemory up\n");
return;
}
else{
curr->num = no;
curr->next = NULL;
printf("%d\n",curr->num);
}
}
void hellop(){
printf("%d", head->num);
}
int main(){
int i;
curr = head;
for(i=1;i<10;i++){
addNode(i);
}
print();
/*head = memAlo();
head->num = 1;
head->next = NULL;
hellop();*/
}
I am sure I have messed up somewhere. The thing is that the head pointer doesn't get the memory allocated by the memAlo() fn() but how to get there? Please help
What I am trying is to create a singly linked list holding numbers from 1 to 9 and to print them using print(). Actually AddNode() is to create single node at the end of the linked list each time the for loop in main() executes.
You set head = NULL at the point where you first defined head. Except in that one place, we never see head on the left-hand side of = anywhere in your program. So of course head is always equal to NULL and never anything else.
You will probably want to insert some code at the start of your addNode function to test whether head == NULL at that point; and if that is true, you will want to assign the result of memAlo() to head instead of curr. You will have to adjust some of the other logic as well.
Your code for allocating a node is wrong. It should create a node, make some space for it, then return it.
struct node *memAlo() {
struct node *nd = malloc(sizeof(*nd));
return nd;
}
This creates a pointer to a node, properly allocates it, then returns it.
Problems I see:
Not dealing with empty list, i.e. when head == NULL.
Creating nodes that are not linked to each other.
curr = memAlo();
allocated memory for a node and returns it to you, but it does not connect the node with anything else.
Try this:
void addNode(int no){
struct node* temp = NULL;
// Deal with an empty list.
if ( head == NULL )
{
head = memAlo();
head->num = no;
head->next = NULL;
}
// Move curr until we reach the last node of the list.
curr = head;
while(curr->next != NULL){
curr = curr->next;
}
temp = memAlo();
if(temp == NULL){
printf("\nmemory up\n");
return;
}
else{
// Link the new node to the previous last node.
temp->num = no;
temp->next = NULL;
printf("%d\n",temp->num);
curr->next = temp;
}
}
It seems that since head is initially NULL, and then you start allocating nodes without saving the address of the first one, you lose the address of the first one, and then can't walk the list from the beginning.
The part you commented out illustrate the problem.
As a side note, there is no free in your program. Remember to always free the memory you alloc
#include<stdio.h>
#include<stdlib.h>
struct node
{
int num;
struct node *next;
};
struct node *head, *curr;
struct node *pos;
void addNode(int n)
{
if(head==NULL)
{
head = (struct node*)malloc(sizeof(struct node));
head->num = n;
head->next = NULL;
curr = head;
}
else
{
while(curr != NULL)
{
pos = curr;
curr = curr->next;
}
curr = (struct node*)malloc(sizeof(struct node));
curr->num = n;
curr->next = NULL;
pos->next = curr;
}
}
void printList()
{
curr = head;
while(curr != NULL)
{
printf("%d",curr->num);
curr = curr->next;
}
}
int main()
{
head = NULL;
curr = head;
int i, a[] = {4,5,1,2,3,9,0};
for(i=0;i<7;i++)
{
addNode(a[i]);
}
curr = head;
printList();
}
This seems to have solved my problem. I figured it out though. Thanks for all your help.

Resources