Removal of items with duplicate data - c

I'm writing a function that removes the consecutive items with duplicate data .
e.g
For example, passing in the list
->a->b->c->c->a->b->b->b->a->null
should result in
->a->b->c->a->b->a->null
The list item definition and function declaration are given below
struct litem {
char data;
litem* next;
};
Mo code looks like
int remove_dumplicates(litem *&list)
{
int count = 0;
struct litem * current = NULL;
current = list;
struct litem *deleteNode;
if (current == NULL ) return;
while(current->next != NULL)
{
if ( current->data == current->next->data) // check for the duplicates
{
count++;
deleteNode =current->next;
current>next= current->next->next;
delete deleteNode;
}
return (count);
}
}
Is this a correct way of achieving the desired result ?

I don't see current being incremented to current->next.
Take as an example a list with all unique elements a -> b -> c and see how your program works.
To fix this you need:
while(current->next != NULL) {
if ( current->data == current->next->data) {
// delete duplicates .
} else {
current = current -> next;
}
}// end-while
return (count);

You need to add an else inside the while loop to advance to the next node:
if( current-> data == current->next->data ) {
....
} else {
current = current->next;
}
Also the returns need to be fixed (the first should return 0 and the second should be moved outside the while loop).

Some quick observations:
The return (count) statement might be outside the while loop, otherwise the loop would be terminated prematurely.
A statement like current = current->next; is required inside the while loop. Otherwise, the loop would become an infinite loop.

current should move to current->next on no duplicate match.
Argument passed to the function should be merely *list (ie. a pointer to an element of type struct litem)
delete is a C++ keyword. Use free() instead.
The modified code:
int remove_duplicates(struct litem *list)
{
int count = 0;
struct litem * current = NULL;
current = list;
struct litem *deleteNode;
if (current == NULL ) return;
while(current->next != NULL)
{
if ( current->data == current->next->data)
{
count++;
deleteNode = current->next;
current->next= current->next->next;
free(deleteNode);
}
else
{
current = current->next;
}
}
return (count);
}

Try this:
int remove_duplicates(litem *&list)
{
int count = 0;
struct litem * current = NULL;
current = list;
struct litem *deleteNode;
if (current == NULL ) return 0;
while(current->next != NULL)
{
if (current->data == current->next->data) // check for the duplicates
{
count++;
deleteNode =current->next;
current->next= current->next->next;
delete deleteNode;
}
else
{
current = current->next;
}
}
return (count);
}

Related

Problem passing non-duplicate entries from two linked lists to a third

I tried to make a function, that takes two linked lists' heads as an input, and creates a third one, that only includes the entries from both lists, that only appear in their respective list. The problem is that when I print the third list, I see that it includes every entry from both lists.
Example list 1: 1->13->32->4->5, list 2: 2->13->42->5
Desired outcome: list 3 1->32->4->2->2, actual outcome: 1->13->32->4->5->2->13->42->5
The head of every list is declared as a global variable.
typedef struct list_path *lp;
struct list_path
{
int row,column;
lp next;
};
lp head_list_1,head_list_2,head_list_3,temp_list,aux_path,temp_union,temp_insert_union,aux_union,aux_path_1,aux_path_2,head_list;
void path_union(lp head_list_1, lp head_list_2)
{
aux_path_1 = head_list_1;
aux_path_2 = head_list_2;
int exist;
while (aux_path_1 != NULL)
{
exist = 0;
while (aux_path_2 != NULL)
{
if (aux_path_1->row == aux_path_2->row && aux_path_1->column == aux_path_2->column)
{
exist=1;
}
aux_path_2 = aux_path_2->next;
}
if (exist == 0)
{
insert_union(head_list_3, aux_path_1->row, aux_path_1->column);
}
aux_path_1 = aux_path_1->next;
}
aux_path_1 = head_list_1;
aux_path_2 = head_list_2;
while (aux_path_2 != NULL)
{
exist = 0;
while (aux_path_1 != NULL)
{
if (aux_path_2->row == aux_path_1->row && aux_path_2->column == aux_path_1->column)
{
exist = 1;
}
aux_path_1 = aux_path_1->next;
}
if (exist == 0)
{
insert_union(head_list_3, aux_path_2->row, aux_path_2->column);
}
aux_path_2 = aux_path_2->next;
}
}
void insert_union(lp head_list_3, int key_a, int key_b)
{
lp union_temp;
lp list_aux = head_list_3;
while (list_aux->next != NULL)
{
list_aux = list_aux->next;
}
union_temp = (lp)malloc(sizeof(struct list_path));
union_temp->row = key_a;
union_temp->column = key_b;
list_aux->next = union_temp;
union_temp->next = NULL;
}
The first function uses 2 nested whiles to find which entries appear only once and the second one passes those keys to the third list.
The problem is that after the inner while loops as for example after this inner while loop
while (aux_path_2 != NULL)
{
if (aux_path_1->row == aux_path_2->row && aux_path_1->column == aux_path_2->column)
{
exist=1;
}
aux_path_2 = aux_path_2->next;
}
the pointers aux_path_2 and aux_path_1 become equal to NULL. So in next iterations of the outer while loops the inner while loops are skipped due to their conditions like this
while (aux_path_2 != NULL)
that at once evaluate to logical false.
You need to reset the values of the pointers aux_path_2 and aux_path_1 in the beginning of the outer while loops before the inner while loops as for example
while (aux_path_1 != NULL)
{
exist = 0;
aux_path_2 = head_list_2; // <===
while (aux_path_2 != NULL)
{
//...
}
Also as soon as the variable exist is set to 1 there is no sense to continue iterations of the inner while loops.
So the inner for loops should be rewritten as for example
while (aux_path_1 != NULL)
{
exist = 0;
for ( aux_path_2 = head_list_2;
!exist && aux_path_2 != NULL;
aux_path_2 = aux_path_2->next )
{
if (aux_path_1->row == aux_path_2->row && aux_path_1->column == aux_path_2->column)
{
exist = 1;
}
}
//...
There are multiple problems in your code:
the implementation is flawed: you should initialize aux_path_2 = head_list_2 at the beginning of each iteration of the first loop and aux_path_1 = head_list_1 at the beginning of each iteration of the second loop.
the general idea is incorrect: you would only insert elements that are in one list only. Elements common to both lists will be skipped in both loops hence never inserted in the union list. You should instead clone the first list and use the test only in the second loop.
the insert_union function cannot start from an empty list. You should return the updated value of head_list_3 from this function and store it in the caller.
there is no need to use global variables for this task: created or updated list pointers should be returned by both functions.
it is confusing and error prone to hide pointers behind typedefs. Instead of defining lp, define list_path as a typedef for struct list_path and use list_path * to keep pointers visible.
Here is a modified version using an auxiliary function to check if a node has given coordinates. Using small generic functions and variable names helps improve code readability:
#include <stdlib.h>
typedef struct list_path list_path;
struct list_path {
int row, column;
list_path *next;
};
int path_find(list_path *head, int row, int column) {
for (list_path *aux = head; aux != NULL; aux = aux->next) {
if (aux->row == row && aux->column == column)
return 1;
}
return 0;
}
list_path *path_insert(list_path *head, int row, int column) {
list_path *temp;
list_path *aux;
temp = malloc(sizeof(*temp));
if (temp == NULL) {
perror("cannot allocate list_path structure");
abort();
}
temp->row = row;
temp->column = column;
temp->next = NULL;
if (head == NULL) {
// empty list: allocated node is the new head
head = temp;
} else {
// otherwise find the last node of the list
for (aux = head; aux->next != NULL; aux = aux->next) {
continue;
}
// and append the newly allocated node
aux->next = temp;
}
return head;
}
list_path *path_union(list_path *list1, list_path *list2) {
list_path *list3 = NULL;
// clone the first list into list3
for (list_path *aux1 = list1; aux1 != NULL; aux1 = aux1->next) {
list3 = path_insert(list3, aux1->row, aux1->column);
}
// append elements only present in list2
for (list_path *aux2 = list2; aux2 != NULL; aux2 = aux2->next) {
if (!path_find(list1, aux2->row, aux2->column)) {
list3 = path_insert(list3, aux2->row, aux2->column);
}
}
// return a pointer to the union list.
return list3;
}

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.

Iterative method to Recursive method C Language

I have tried to convert this method that is already working in my program to recursive way. Because I was asked to do it. The thing is I have tried see below but in my method when try to add to he position the method value this value is a great number and create segmentation.
This is my method in iterative way:
int researchList_getPosByCountry(tResearchList* list, tCountry *country) {
// Check preconditions
assert(list != NULL);
tResearchListNode *prev = NULL;
int pos;
// check if is an empty list
if (researchList_empty(list)) {
pos = -1;
}
else{
pos = 1;
prev = list->first;
while ((prev != NULL) && !country_equal(prev->e->country, country) ) {
prev = prev->next;
pos++;
}
}
if (prev == NULL) {
pos = -1;
}
return pos;
}
This is my method in recursive way:
assert(list != NULL);
tResearchListNode *prev;
int pos;
// check if is an empty list
if (researchList_empty(list)) {
pos = -1;
}
else{
pos = 1;
prev = list->first;
if ((prev != NULL) && !country_equal(prev->e->country, country) ) {
prev = prev->next;
pos = pos + researchList_getPosByCountry(list, country); //Debugging the segmentation is here
}
}
You will get an endless recursion, since you call researchList_getPosByCountry always starting from the begin of the list; again and again and ...
I suggest you introduce a second (then recursively used) function that calls itself with the respective next node and returns (a) the "greatest" negative number possible if the node was not found (thereby turning any intermediate results on the call stack into a negative one), or return 0 to denote "country found, take the count so far", or "1 + next try" to continue counting. The recursive part could look as follows; you need then to call this one from your int researchList_getPosByCountry(tResearchList* list, tCountry *country) and interpret a negative result accordingly:
int researchList_getPosByCountry(tResearchListNode* node, tCountry *country) {
if (!node) {
return INT_MIN;
} else if (countryEqual(...)) {
return 0;
} else {
return 1 + researchList_getPosByCountry(node->next,country);
}
}

Check if Linked List is sorted (ascending order) or not in C?

struct node* acc_check(struct node *head) {
int count = 0, count2 = 0;
for (struct node *ptr = head; ptr->next != NULL; ptr = ptr->next) {
count++;
if (ptr->data <= ptr->next->data) {
count2++;
}
}
if (count == count2)
printf("Ascending Order");
else
printf("Not in Ascending Order");
return head;
}
I am always getting "Ascending Order", please help me to figure out the problem.
Here is the full source code, LINKED LIST CODE
If you look carefully to your code, you are sorting the elements of the list when creating the list:
case 1: {
head = create_11(head);
head = sort_list(head);
}
If you comment the sorting of the list you will obtain the expected result.
Independent on whether the list is already sorted or not in any case the function is incorrect.
For starters it can have undefined behavior because the user can call the function for an empty list. In this case this expression
ptr->next != NULL
will invoke undefined behavior.
The function shall not output any message. It is the caller of the function will decide whether to output any message. What it shall do is to return integer value either 0 or 1 reporting whether the list is unsorted or sorted.
Moreover to make the conclusion that the list is not sorted there is no need to traverse it to its end. The variables count and count2 do not make sense. They are redundant.
The function can be defined the following way.
int acc_check( const struct node *head )
{
if ( head != NULL )
{
const struct node *prev = head;
while ( ( head = head->next ) != NULL && !( head->data < prev->data ) )
{
prev = head;
}
}
return head == NULL;
}

How can I display the data I created in a linked list?

I think there is something wrong with my create.
void add(N *p) {
N *current, *start;
current = malloc(sizeof(p));
scanf("%d", &current->data);
current->next = NULL;
if (p == NULL) {
p = current;
start = current;
} else {
start->next = current;
start = current;
}
}
I think that my display() is correct.
void display(N *p) {
N *current;
current = p;
while (current != NULL) {
printf("\n%d", current->data);
current = current->next;
}
}
Your malloc(sizeof(p)) only returns enough space for a pointer. You instead want malloc(sizeof(N)).
Also, you need to return the new value of p instead of throwing it away at the end of add(). (Your start has a similar issue; pick one to be the head of your linked list.)
There are problems:
function add() does not allocate the correct amount of memory. Use this method:
current = malloc(sizeof(*current));
The way you are inserting the newly allocated object into the list does not work: you modify p, which is an argument with local scope, and you set start which also has local scope. No side effect is performed on the N pointer is the callers scope.
Your display function is correct, but I would favor adding the newline at the end of the output instead of at the beginning.
Here is an updated version with a better API:
int add(N **headp) {
N *current = calloc(sizeof(*current));
if (current == NULL) {
fprintf(stderr, "cannot allocate memory for new object\n");
return -1;
}
if (scanf("%d", &current->data) != 1) {
fprintf(stderr, "cannot read value for new object\n");
return -2;
}
current->next = *headp;
*headp = current;
return 0;
}
void display(const N *list) {
for (const N *p = list; p != NULL; p = p->next) {
printf("%d\n", p->data);
}
}
The add function is used this way from the caller:
#include <stdio.h>
#include <stdlib.h>
typedef struct N {
int data;
struct N *next;
} N;
int main(void) {
N *list = NULL;
for (i = 0; i < 10; i++) {
if (add(&list))
break;
}
display(list);
return 0;
}

Resources