Iterative method to Recursive method C Language - c

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);
}
}

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.

The functions && Linked List

I did my best with this program but I could not know where is the error?? I'll explain the program. In this program I should implement a stack of integers as linked list, using a global variable to point to the top of the stack by using these methods:
int push(int i);
push i on the stack, return 1 if successful else return 0.
int pop();
pop number from stack. if stack empty return 0;
I did create new method call int stackEmpty(); and the two method above.
Every time I run my program it's push the numbers into the stack but the pop doesn't work. Here my code:::
#include <stdio.h>
#include <stdlib.h>
typedef struct stack Stack;
struct stack
{
int number;
Stack *next;
};
Stack *top = NULL;
int push(int i);
int count();
int stackEmpty();
int pop();
int main()
{
char op;
int i, x;
printf("Welcome to my stack\n");
printf("p to pop, s to push, c to count, q to quit\n");
while (op != 'q')
{
scanf("%c", &op);
if (op == 'p')
{
x = pop();
if (x == 0)
{
printf("Stack is empty\n");
}
else
{
printf("%d popped\n", pop());
}
}
else if (op == 'c')
{
i = count();
printf("%d numbers on stack\n", i);
}
else if (op == 's')
{
printf("Enter number: ");
scanf("%d", &i);
x = push(i);
if (x == 1 || x == 2)
{
printf("%d puched :: state%d\n", i, x);
}
else
{
printf("faill %d\n", x);
}
}
else if (op == 'q')
{
return 0;
}
}
return 0;
}
int stackEmpty()
{
if (top == NULL)
{
return 1;
}
else
{
return 0;
}
}
int count()
{
int counter = 0;
if (top == NULL)
{
return counter;
}
else
{
while (top != NULL)
{
top = top->next;
counter++;
}
return counter;
}
}
int push(int i)
{
Stack *head;
Stack *next;
Stack *new;
int state;
int m;
head = top;
new = (Stack *) malloc(sizeof(Stack));
if (new == NULL)
{
state = 0;
} new->number = i;
m = stackEmpty();
if (m == 1)
{
head = new;
top = head;
head->next = NULL;
state = 1;
}
else
{
while (head != NULL)
{
if ((next = head->next) == NULL)
next = new;
next->next = NULL;
state = 2;
break;
head = top->next;
next = head->next;
}
top = head;
}
return state;
}
int pop()
{
Stack *head;
int state;
int m;
head = top;
if (head == NULL)
{
state = 0;
}
m = stackEmpty();
if (m == 1)
{
state = 0;
}
else
{
state = head->number;
top = head->next;
free(head);
}
return state;
}
Several problems:
top is your supposed head of the stack I assume. In count you advance top until it is NULL - thus once you called count you have "lost" your stack.
A stack is a LIFO queue (last in first out). Your push would implement a FIFO (first in first out) by appending new elements at the end.
Your push is not actually adding anything to the list. You are just assiging new to next but you are not pointing to next from anywhere in your list.
When using pop you are calling it twice (once for removing the element and once for printing). Therefore you remove two elements whenever you go down that code path. A better implementation would be to write a peek function which returns the top element without removing it and the pop function simply removes it (indicating success with 1 and fail with 0)
A push for a stack goes like this:
Create a new element
Point to your current head as the next element
Make your new element the new head of the stack
No loop needed. It's an O(1) operation.
You are not pushing correctly. You are changing next which is a local variable. you are not changing the "next" value in you list tail.
One problem is that you pop(), then check result, then pop() again while printing. You're popping twice for each time you try to print.
Another error:
while (head != NULL)
{
if ((next = head->next) == NULL)
next = new;
next->next = NULL;
state = 2;
break;
head = top->next;
next = head->next;
}
Should be:
while (head != NULL)
{
if ((next = head->next) == NULL)
{
next = new;
next->next = NULL;
state = 2;
break;
}
head = top->next;
next = head->next;
}
At least, that's what your original indentation seems to indicate.

linked list delete function

The following code snippet is not working right.
void deleteNode(list **start, int pos) {
int currentPosition=0;
list *currentNode;
list *nodToDelete;
currentNode = *start;
if (currentNode == NULL) {
printf("Empty List\n");
} else if (pos == 0 ) {
nodToDelete = *start;
*start = nodToDelete->next;
free(nodToDelete);
} else {
while (currentNode->next != NULL) {
if (currentPosition >= pos -1) {
break;
}
currentPosition++;
currentNode = currentNode->next;
}
if (currentPosition < pos -1 || currentNode->next == NULL) {
printf("No node at given position exists\n");
} else {
nodToDelete = currentNode->next;
currentNode = nodToDelete->next;
free(nodToDelete);
nodToDelete = NULL;
}
}
}
void displayList(list *node) {
if (node == NULL) {
printf("Empty List");
}
while (node != NULL) {
printf("%d\t", node->data);
node = node->next;
}
printf("\n");
}
int main()
{
list *start, *node;
start = NULL;
insertNode(&start, 2);
insertNode(&start, 3);
insertNode(&start, 4);
insertNode(&start, 1);
insertNode(&start, 5);
deleteNode(&start, 3);
displayList(start);
}
When executed the output is
Before Deletion 2 3 4 1 5
After Deletion 2 3 4 0 5
It is supposed to delete 1 but it is inserting 0 at its place.
Here is something that might work --
Replace
currentNode = nodToDelete->next;
with
currentNode->next = nodToDelete->next;
You basically need the node before the nodetodelete to have its next to point to the node that nodetodelete used to point to
Once you've found the node you want to take out of the list, you need to actually take it out. =)
...
nodToDelete = currentNode->next;
currentNode->next = nodToDelete->next;
free(nodToDelete);
...
Besides the problem with currentNode->next = nodToDelete->next; and negative positions you are mixing your ui and your logic. As much as possible you should separate the two.
Sending something to the ui is a way of reporting progress; whether the ui is a command line, a browser or a speaker. Within deleteNode, an empty list or a position that is out of bounds, is not progress. Sequentially both are the same as success - you are done. If you want failure to be to be reported, that should be done where it can lead to a separate sequence...i.e the caller. Also, by mixing in ui, you introduce an unnecessary dependency and failure (what if there's a bug in printf, YOUR function will crash when it doesn't doesn't have to). If you're function returns a defined result, the caller can decide if/how to report that result, including success (your function currently doesn't do so, and the caller has no way telling the difference between sucess or failure).

Removal of items with duplicate data

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);
}

Resources