this is my first time asking here.
I was practicing linked list in C and I cannot figure out why my functions behave differently.
I make a linked list of ints 1-10 and delete the even numbers using delEven() function.
delEven() plays with the node P, P=*node, to make the changes, which work properly.
However, when I use the P=*node to delete all elements in the list in delAll2, the list is untouched. When I ran printList(P) within the function delAll2, the list is properly deleted.
When I use the input *node instead of P to delete all elements in delAll, it is working properly.
I would like to understand why I was able to delete even elements in delEven using P=*node, when I was not in delAll2.
Thanks,
code:
#include <stdio.h>
#include <stdlib.h>
struct node
{
int dat;
struct node* next;
};
void printList (struct node* node)
{
if (node == NULL)
{
printf("empty\n");
return;
}
while (node->next!=NULL)
{
printf("%2d",node->dat);
node = node->next;
}
printf("%2d\n",node->dat);
}
void delEven(struct node** node)
{
struct node* P;
P = *node;
while (P->next != NULL)
{
if (P->next->dat%2==0)
{
P->next = P->next->next;
}
if(P->next->dat%2==0)
{
P->next = P->next->next;
}
P=P->next;
}
}
void delAll(struct node** node)
{
struct node* P;
P = *node;
while ((*node)->next != NULL)
{
*node = (*node)->next;
}
*node = (*node)->next;
}
void delAll2(struct node** node)
{
struct node* P;
P = *node;
while (P != NULL)
{
P = P->next;
}
}void main()
{
int i;
struct node* start;
struct node* Q;
struct node* P;
start = NULL;
for(i=1; i<=10;i++)
{
Q=malloc(sizeof(struct node));
Q->dat = i;
Q->next = start;
start = Q;
}
printList(start);
printList(start);
delEven(&start);
printList(start);
delAll2(&start);
printList(start);
}
output when delAll2:
10 9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1
10 9 7 5 3 1
10 9 7 5 3 1
output when delAll:
10 9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1
10 9 7 5 3 1
empty
When managing linked lists, you should avoid having multiple versions of code to do the same thing in multiple locations.
Make a single function to delete a node. I recommend one that looks like this:
void deleteNextNode(struct node **list, struct node *node_before);
// node_before is the node _before_ the node to delete
// node_before == NULL to delete the first node in the list
// *list is updated if necessary
Once you have that, you can rewrite your delEven() as:
void delEven(struct node **list)
{
// Delete all even-valued nodes at the head of the list
while (*list && isEven(list->dat))
deleteNextNode(list, NULL);
if (!*list) return; // (it might have been the whole list)
// Find and delete even-valued nodes in the rest of the list
struct node *before = *list; // (list might be a single node at this point)
while (before->next)
// if the next node is even, delete it
if (isEven(before->next->dat))
deleteNextNode(list, before);
// else advance to the next “before” node
else
before = before->next;
}
Notice how we had to handle the (head of list) and (rest of list) cases separately?
Related
This is my code for insertion in the end of a circular linked list for which I am getting correct result
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node *head;
void insert(int val)
{
struct node *temp;
struct node *tail;
temp = (struct node *)malloc(sizeof(struct node));
temp->data = val;
if (head == NULL)
{
head = temp;
tail = temp;
temp->next = head;
}
else
{
tail->next = temp;
tail = temp;
tail->next = head;
}
}
void printlist()
{
struct node *temp = head;
printf("The elements of the linked list area \n ");
while (temp->next != head)
{
printf("%d ", temp->data);
temp = temp->next;
}
printf("%d ", temp->data);
printf("%d", temp->next->data);
}
int main()
{
int n, i, val;
printf("Enter how many elements in a circular likedlist you want \n");
scanf("%d",&n);
head = NULL;
for(i=0;i<n;i++)
{
// printf("Enter the value\n");
// scanf("%d,&val");
insert(i);
}
printlist();
}
for which the output is
Enter how many elements in a circular likedlist you want
10
The elements of the linked list area
0 1 2 3 4 5 6 7 8 9 0
However, for the same code when I try to take values from the user it gives me incorrect output.here in this code I just changed a part of the main function inside the for loop where I am taking input for the val instead of passing an integer in function insert
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node *head;
void insert(int val)
{
struct node *temp;
struct node *tail;
temp = (struct node *)malloc(sizeof(struct node));
temp->data = val;
if (head == NULL)
{
head = temp;
tail = temp;
temp->next = head;
}
else
{
tail->next = temp;
tail = temp;
tail->next = head;
}
}
void printlist()
{
struct node *temp = head;
printf("The elements of the linked list area \n ");
while (temp->next != head)
{
printf("%d ", temp->data);
temp = temp->next;
}
printf("%d ", temp->data);
printf("%d", temp->next->data);
}
int main()
{
int n, i, val;
printf("Enter how many elements in a circular likedlist you want \n");
scanf("%d",&n);
head = NULL;
for(i=0;i<n;i++)
{
printf("Enter the value\n");
scanf("%d,&val");
insert(val);
}
printlist();
}
For this program, the output I am getting is
Enter how many elements in a circular likedlist you want
5
Enter the value
1
The elements of the linked list area
0 0
Can anyone suggest me where my code is going wrong?
Symptoms: "It worked, then it didn't." This is the hallmark of UB. Your compiler didn't output code that affected the stack between iterative calls in your first example. The bytes used for tail during each invocation were not overwritten. In the second example ("user input"), scanf() has made use of the same region of stack (as it should), and the fortunate behaviour of the first example became unfortunate. This is why "It worked, then it didn't." Undefined behaviour has many guises...
If you want to be respected as a coder, you don't use global variables, and then compound the mistake with adding more globals. Or 'scanning' what could be millions of nodes to find the tail of a LL.
The code below declares an ordinary node, and a special header node that are compatible.
The testing in main() uses two LLs; one for some integer values, and one that grows with only the odd numbered integer values.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
} node_t;
typedef struct {
int data; // NB: same name & order of 1st two struct members
node_t *next; // (ditto)
node_t *tail; // head knows where its backend is
int cnt; // meta-information becomes simple to implement
int id;
} head_t;
head_t *append( head_t *ph, int val ) {
static int take_a_number = 0;
node_t *nn = (node_t *)calloc( 1, ph ? sizeof(node_t) : sizeof(head_t) );
/* omitting check */
nn->data = val;
nn->next = nn; // for now, a 'ringlet'
if( ph == NULL ) {
ph = (head_t*)nn; // notice the casting of compatible struct entities
ph->tail = nn;
ph->id = ++take_a_number;
} else {
nn->next = (node_t*)ph;
ph->tail = ph->tail->next = nn;
}
ph->cnt++;
// debug traversal showing results
printf( "list #%d - %d nodes: ", ph->id, ph->cnt );
node_t *p = (node_t*)ph;
do
printf( "%d ", p->data );
while( (p = p->next) != (node_t*)ph );
puts( "" );
return ph;
}
int main() {
int i;
// two lists. Could be 100, or an array of them...
head_t *p1 = NULL, *p2 = NULL;
for( i = 7; i <= 49; i += 7 ) { // just some arbitrary data
p1 = append( p1, i );
if( i%2 )
p2 = append( p2, i );
}
printf( "Two laps around first list: " );
node_t *pFun = (node_t*)p1;
for( i = 2*p1->cnt + 1; i; i-- )
printf( "%d ", pFun->data ), pFun = pFun->next;
puts( "" );
/* omitting `free()` of heap */
return 0;
}
Output
list #1 - 1 nodes: 7
list #2 - 1 nodes: 7
list #1 - 2 nodes: 7 14
list #1 - 3 nodes: 7 14 21
list #2 - 2 nodes: 7 21
list #1 - 4 nodes: 7 14 21 28
list #1 - 5 nodes: 7 14 21 28 35
list #2 - 3 nodes: 7 21 35
list #1 - 6 nodes: 7 14 21 28 35 42
list #1 - 7 nodes: 7 14 21 28 35 42 49
list #2 - 4 nodes: 7 21 35 49
Two laps around first list: 7 14 21 28 35 42 49 7 14 21 28 35 42 49 7
0 global variables, and traversing the LL is only done when printing. This is part of structured programming.
The easiest fix is probably to make tail a global variable like head. I also refactored insert() to reduce duplication, added error checking for malloc() and scanf(), tweaked printlist() to not print the head twice:
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *head;
struct node *tail;
void insert(int val) {
struct node *temp = malloc(sizeof(*temp));
if(!temp) {
printf("malloc failed\n");
exit(1);
}
temp->data = val;
if (head == NULL) {
head = temp;
} else {
tail->next = temp;
}
tail = temp;
tail->next = head;
}
void printlist() {
printf("The elements of the linked list area \n ");
for(struct node *temp = head; temp; ) {
printf("%d ", temp->data);
temp = temp->next;
if(temp == head) break;
}
printf("\n");
}
int main(void) {
printf("Enter how many elements in a circular likedlist you want \n");
int n;
if(scanf("%d", &n) != 1) {
printf("scanf failed\n");
return 1;
}
head = NULL;
for(int i=0; i<n; i++) {
insert(i);
}
printlist();
}
and it the output is now:
The elements of the linked list area
0 1 2 3 4 5 6 7 8 9
You could eliminate the head pointer (tail->next == head) if you want.
In the insert function, the else branch is dereferencing pointer variable tail that has not been initialized. (The variable tail has automatic storage class, i.e. it is a "stack" variable, so it's value is not preserved between calls to the function.) The tail variable needs to point to the last element on the list.
The function can be changed to search for the last element of the list like this:
void insert(int val)
{
struct node *temp;
struct node *tail;
temp = (struct node *)malloc(sizeof(struct node));
temp->data = val;
if (head == NULL)
{
head = temp;
}
else
{
/* find last element */
for (tail = head; tail->next != head; tail = tail->next)
;
tail->next = temp;
}
temp->next = head;
}
(However, it probably makes more sense to store the tail statically outside the function as in Allan Wind's answer so that the function does not have to waste time finding the last element of the list each time it is called. It should also check for memory allocation failure, as in that answer.)
The printList function does not currently work if the list is empty. It will dereference head even if it is NULL, leading to undefined behavior. That can be fixed by moving the all code that accesses the elements of the list inside a if (head != NULL) { } block:
void printlist(void)
{
struct node *temp = head;
printf("The elements of the linked list are \n ");
if (head != NULL)
{
while (temp->next != head)
{
printf("%d ", temp->data);
temp = temp->next;
}
printf("%d ", temp->data);
printf("%d", temp->next->data);
}
printf("\n");
}
Can someone explain me why this code give me as result the empty list:
typedef struct str_node{
int data;
struct str_node *next;
}node;
void begin(node *head);
void display_list(node *head);
int main(){
node *head;
int i;
head = NULL;
for(i=0;i<5;i++) {
begin(head);
}
display_list(head);
return 0;
}
void begin(node *head){
node *new;
int value;
new = (node*) malloc(sizeof(node));
printf("Insert the element to add at the beginning of the list: ");
scanf("%d",&value);
new->data = value;
new->next = head;
head = new;
}
But if i change the begin() function with the pointer to pointer it gives to me the right list?
void begin(node **head){
node *new;
int value;
new = (node*) malloc(sizeof(node));
printf("Insert the element to add at the beginning of the list: ");
scanf("%d",&value);
new->data = value;
new->next = *head;
*head = new;
}
Can you also explain me why when i pass in the main the node head to the function begin i have to pass it as "&head"? and no more as "head"
In the first program in this code snippet
head = NULL;
for(i=0;i<5;i++) {
begin(head);
}
the pointer head is passed to the function begin by value. That is a copy of the value of the pointer head declared in main is created and is assigned to the parameter with the same name of the function begin
void begin(node *head);
So within the function it is the parameter head that holds initially a copy of the original pointer head that is changed. The original pointer head the value of which was assigned to the parameter is not being changed.
To change the original pointer head declared in main you have to pass it to the function by reference indirectly through a pointer to the pointer head as it is done in the second program.
So the function should be declared like
void begin(node **head);
And you have to pass the pointer head indirectly through a pointer to it
begin( &head );
In this case dereferencing the passed pointer the function will get a direct access to the original pointer head declared in main and can change it (not a copy of its value as it takes place in the first function definition)
new->next = *head;
*head = new;
To make it more clear consider this simple demonstrative program.
#include <stdio.h>
typedef int T;
void f( T t )
{
t = 10;
}
int main(void)
{
T t = 0;
printf( "Before calling f t is equal to %d\n", t );
f( t );
printf( "After calling f t is equal to %d\n", t );
return 0;
}
Its output is
Before calling f t is equal to 0
After calling f t is equal to 0
As the function f deals with a copy of the value of the passed argument the value of the variable t declared in main was not changed.
So you need to pass the original variable t by reference through pointer like
#include <stdio.h>
typedef int T;
void f( T *t )
{
*t = 10;
}
int main(void)
{
T t = 0;
printf( "Before calling f t is equal to %d\n", t );
f( &t );
printf( "After calling f t is equal to %d\n", t );
return 0;
}
Now the program output is
Before calling f t is equal to 0
After calling f t is equal to 10
In these demonstrative programs the name T is used as an alias for the type int and in main the object t has this type.
Let's now assume that the name T is an alias for the type int *.
typedef int * T;
In this case a declaration in main as for example
T t = NULL;
means that the variable t has the pointer type int *. That is it is equivalent to
int * t = NULL;
So to pass it to a function that must change the original variable t we need to pass it by reference like
f( &t );
that means that the corresponding function shall have the parameter type declared like
void f( T *t );
but as T is an alias for int * hence it means that the function has a parameter of the type int **.
void f( int * *t );
Because head is (effectively) a local variable, so changing it has no effect outside of the function, whereas changing *head changes what head points to, and thus does.
If you wanted a function to be able to change the value in an int variable (say, x), you would pass it a pointer to x, which would have the type int* and you would get the pointer to x by using &x. The same holds no matter what type x is.
A bit of confusion may come from declaring
node *head;
instead of
node* head;
You are declaring head. head is the variable and it is a pointer. It is not a node. Note also that a node is not a linked list: a linked list is a collection of nodes and possibly something else in order to have an useful implementation. More on this later at the end.
Fact is you have in main() declared head, just a node*. The node itself does not even exist yet. You declared begin() as
void begin(node *head);
and I think you will see it more clearly as
void begin(node* parameter);
parameter is node*.
Inside begin() you get a copy of the pointer and changing the pointer will not change the original pointer in main().
In your case it will in main() forever point to NULL.
What matters is that a pointer is like any variable: A pointer has an address. And a content. When you pass by value, just like you did, the pointer in begin() starts with NULL, the VALUE that came from main(). But the bond between them ends int the call: the initial value.
When you pass a pointer to begin(), using the operator 'address of' and writing &head things change: you will change it using the operator '*' meaning that you will change the address it points to, so it will change in main(). Since head is node* a pointer to it will be declared as node**
But consider changing the declaration of begin() for a linked list using:
node* begin(node* node);
The logic is that inserting a node can change the head of the list, so you return the new address, as in
node* _insert_begin(int value, node* pNode)
{
node* new = (node*)malloc(sizeof(node));
new->data = value;
new->next = pNode;
return new;
}
is a common way to write this. Another is to use node**.
The way I am describing here, any operation that can change the head of the list must
return the new head
receive and update a pointer to the pointer of the head
See again this code that inserts at the beginning of the list:
node* _insert_begin(int value, node* pNode)
{ // insert 'value' at the start of the list
node* new = (node*)malloc(sizeof(node));
(*new).data = value;
new->next = pNode;
return new;
}
returning new you get head updated. And you can write in main()
node* another = NULL;
display_list(another);
// inserts 5 to 0 at the beginning
for (int i = 5; i >= 0; i -= 1)
another = _insert_begin(i, another);
printf("inserted 5..0 at the beginning\n");
display_list(another);
Note the line another = _insert_begin(i, another); and you see how the pointer in main() gets updated.
This is the output
empty list
inserted 5..0 at the beginning
0 1 2 3 4
5
list has 6 elements
Using this implementation of display_list(), that prints 5 values per line:
int display_list(node* p)
{
if (p == NULL)
{
printf("empty list\n");
return 0;
};
int count = 0;
// not empty
do
{
printf("%8d ", p->data);
count++;
if (count % 5 == 0) printf("\n");
p = p->next;
} while (p != NULL);
if (count % 5 != 0) printf("\n");
printf("list has %d elements\n", count);
return count;
};
Another example: inserting at the end
note that inserting at the end can also change the head, in the case that the list is empty, so we still need to return the head address
node* _insert_end(int value, node* pNode)
{ // insert value at the end of the list
node* new = (node*)malloc(sizeof(node));
new->data = value;
new->next = NULL;
if (pNode == NULL) return new;
node* p = pNode;
while (p->next != NULL) p = p->next;
p->next = new;
return pNode;
}
Another use: inserting in ascending order
Sure, inserting in ascending order can also change the head, as in
node* _insert_ordered(int value, node* pNode)
{ // insert value at ascending order in the list
node* new = (node*)malloc(sizeof(node));
new->data = value;
new->next = NULL;
if (pNode == NULL) return new;
node* p = pNode;
node* prev = NULL; // previous node: list if forward only
while (p->next != NULL)
{
if (new->data < p->data)
{
// insert before first greater than value
if (prev == NULL)
{
// new head
new->next = p;
return new;
}; // if()
prev->next = new;
new->next = p;
return pNode; // no change in head
};
prev = p; p = p->next; // updates pointers
}; // while()
// we are at the end: new will be the last?
if (new->data < p->data)
{
if (prev == NULL)
pNode = new;
else
prev->next = new;
new->next = p;
}
else
{
p->next = new;
};
return pNode;
} // _insert_ordered()
Deleting a list
Delete a list should also return a node* in order to invalidade the head pointer. It is usual. As you get used to the mechanic of it this ensures that an invalid pointer does not remain around.
Note that this logic is cooperative: you must assign the head pointer back at every call that can change the head
node* delete_list(node* H)
{
if (H == NULL) return NULL;
if (H->next == NULL)
{ // single node
free(H);
return NULL;
};
// more than one node
do
{ node* p = H->next;
free(H);
H = p;
} while (H != NULL);
return NULL;
};
A running program
Output of the example program
empty list
inserted 5..0 at the beginning
0 1 2 3 4
5
list has 6 elements
inserted 6 to 10 at the end
0 1 2 3 4
5 6 7 8 9
10
list has 11 elements
inserted 0 to 10, ordered
0 0 1 1 2
2 3 3 4 4
5 5 6 6 7
7 8 8 9 9
10 10
list has 22 elements
inserted -1 to -10, ordered
-10 -9 -8 -7 -6
-5 -4 -3 -2 -1
0 0 1 1 2
2 3 3 4 4
5 5 6 6 7
7 8 8 9 9
10 10
list has 32 elements
inserted 11 to 20, ordered
-10 -9 -8 -7 -6
-5 -4 -3 -2 -1
0 0 1 1 2
2 3 3 4 4
5 5 6 6 7
7 8 8 9 9
10 10 11 12 13
14 15 16 17 18
19 20
list has 42 elements
about to delete list
empty list
The example C program
#include <stdio.h>
#include <stdlib.h>
typedef struct str_node
{
int data;
struct str_node* next;
} node;
void begin(node* pNode);
node* delete_list(node*);
int display_list(node*);
node* _insert_begin(int, node*);
node* _insert_end(int, node*);
node* _insert_ordered(int, node*);
int main()
{
node* another = NULL;
display_list(another);
// insert 5 to 0 at the beginning
for (int i = 5; i >= 0; i -= 1)
another = _insert_begin(i, another);
printf("inserted 5..0 at the beginning\n");
display_list(another);
// insert 6 to 10 at the end
for (int i = 6; i <= 10; i += 1)
another = _insert_end(i, another);
printf("inserted 6 to 10 at the end\n");
display_list(another);
// insert 0 to 10 ordered
for (int i = 0; i <=10; i += 1)
another = _insert_ordered(i, another);
printf("inserted 0 to 10, ordered\n");
display_list(another);
// insert -1 to -10 ordered
for (int i = -1; i >= -10; i -= 1)
another = _insert_ordered(i, another);
printf("inserted -1 to -10, ordered\n");
display_list(another);
// insert 11 to 20 ordered
for (int i = 11; i <= 20; i += 1)
another = _insert_ordered(i, another);
printf("inserted 11 to 20, ordered\n");
display_list(another);
printf("about to delete list\n");
another = delete_list(another);
display_list(another);
return 0;
}
node* delete_list(node* H)
{
if (H == NULL) return NULL;
if (H->next == NULL)
{ // single node
free(H);
return NULL;
};
// more than one node
do
{ node* p = H->next;
free(H);
H = p;
} while (H != NULL);
return NULL;
};
node* _insert_begin(int value, node* pNode)
{ // insert 'value' at the start of the list
node* new = (node*)malloc(sizeof(node));
(*new).data = value;
new->next = pNode;
return new;
}
node* _insert_end(int value, node* pNode)
{ // insert value at the end of the list
node* new = (node*)malloc(sizeof(node));
new->data = value;
new->next = NULL;
if (pNode == NULL) return new;
node* p = pNode;
while (p->next != NULL) p = p->next;
p->next = new;
return pNode;
}
node* _insert_ordered(int value, node* pNode)
{ // insert value at ascending order in the list
node* new = (node*)malloc(sizeof(node));
new->data = value;
new->next = NULL;
if (pNode == NULL) return new;
node* p = pNode;
node* prev = NULL; // previous node: list if forward only
while (p->next != NULL)
{
if (new->data < p->data)
{
// insert before first greater than value
if (prev == NULL)
{
// new head
new->next = p;
return new;
}; // if()
prev->next = new;
new->next = p;
return pNode; // no change in head
};
prev = p; p = p->next; // updates pointers
}; // while()
// we are at the end: new will be the last?
if (new->data < p->data)
{
if (prev == NULL)
pNode = new;
else
prev->next = new;
new->next = p;
}
else
{
p->next = new;
};
return pNode;
} // _insert_ordered()
int display_list(node* p)
{
if (p == NULL)
{
printf("empty list\n");
return 0;
};
int count = 0;
// not empty
do
{
printf("%8d ", p->data);
count++;
if (count % 5 == 0) printf("\n");
p = p->next;
} while (p != NULL);
if (count % 5 != 0) printf("\n");
printf("list has %d elements\n", count);
return count;
};
An arguably more useful Linked List structure
Consider the following
struct no
{
void* item;
struct no* next;
struct no* prev;
}; // no
typedef struct no Node;
typedef struct
{ // example, more flexible
char* name;
unsigned size;
unsigned capacity;
Node* head;
Node* tail;
} Linked_list;
This way a linked list is defined as a container of nodes.
It has even an optional name.
size is always available and up to date
a size limit can be implement as capacity
insert at the end and at the beginning does no require you to follow all other nodes, since the list encapsulates pointers to both head and tail
a node has pointers to next AND previous nodes so some data such as playlists or collections like that can be iterated more easily.
a program can have any number of lists since each one encapsulates all of this metadata.
a list can contains anything since the data is a pointer to void, void*
functions like empty() or size() can be implemented easily
all functions use a pointer to the list
Linked_list ll_one;
Linked_list many_ll[20];
Linked_list* pLL = &ll_one;
regarding:
void begin(node *head){
Changing head only changes the call stack 'head', what is needed is to change where 'head' in the caller's function points to. TO do that, the caller must pass the address of 'head'. The fact that 'head' is,itself, a pointer doesn't help with the clarity of what needs to be done,
I am working on trying to add a node to the end of a linked list, but I am receiving cygwin_exception::open_stackdumpfile.
Definition of my Node Struct:
struct Node
{
int number; /* data portion */
struct Node *next; /* pointer portion */
};
Free Memory Function:
void free_list(struct Node *list) {
while(list) {
struct Node *temp = list->next;
free(list);
list = temp;
}
}
Adding Node to End Function:
void add_back(struct Node **list, int value) {
struct Node *node;
struct Node *temp;
node = (struct Node*)malloc(sizeof(struct Node));
if(node == NULL) {
printf("Unable to allocate memory.");
} else {
node->number = value;
node->next = NULL;
temp = *list;
while(temp->next != NULL) {
temp = temp->next;
}
temp->next = node;
}
}
And, last but not least, my test case for above function:
void test_add_back(void)
{
int i;
struct Node *list = NULL;
for (i = 1; i <= 10; i++)
{
printf("add %2i to back: ", i);
add_back(&list, i);
print_list(list);
}
free_list(list);
}
Opposed to my stack dump, I should be getting:
test_add_back ========================================
add 1 to back: 1
add 2 to back: 1 2
add 3 to back: 1 2 3
add 4 to back: 1 2 3 4
add 5 to back: 1 2 3 4 5
add 6 to back: 1 2 3 4 5 6
add 7 to back: 1 2 3 4 5 6 7
add 8 to back: 1 2 3 4 5 6 7 8
add 9 to back: 1 2 3 4 5 6 7 8 9
add 10 to back: 1 2 3 4 5 6 7 8 9 10
In short, I am unsure which piece is causing this stack dump, I feel fairly confident that it is likely an error within my add_back() function but it's also possible that my free_list() function is causing a memory leak.
Anyhow, any help in determining what is causing the stack dump appreciated.
Cheers,
Toby
It is desirable that after deleting all nodes in the list the pointer that points to the head node was equal to NULL.
So it is better to define the function free_list the following way passing the pointer to the head node by reference.
void free_list( struct Node **list )
{
while( *list )
{
struct Node *current = *list;
*list = ( *list )->next;
free( current );
}
}
The function add_back invokes undefined behavior when it is called for an empty list due to these statements
temp = *list;
while(temp->next != NULL) {
because initially *list is equal to NULL.
The function shall not issue any message. It is the caller of the function that will decide whether to issue a message if any. The function shall report whether a new node was appended successfully by returning an integer value equal to 0 or 1.
The function can be defined the following way.
int add_back( struct Node **list, int value )
{
struct Node *node = malloc( sizeof( struct Node ) );
int success = node != NULL;
if ( success )
{
node->number = value;
node->next = NULL;
while( *list != NULL )
{
list = &( *list )->next;
}
*list = node;
}
return success;
}
I wrote a recursive function to reverse a linked list as follows:
struct node{
int val;
struct node *next;
};
//Global pointer to structure
struct node *start=NULL,*head=NULL;
//*Function to input node*
void create(int data){
struct node *temp;
temp=(struct node *)malloc(sizeof(struct node));
if(start == NULL){
temp->val=data;
temp->next=NULL;
start=temp;
head=temp;
}
else{
temp->val=data;
temp->next=NULL;
head->next=temp;
head=temp;
}
}
*Function to reverse the linked list*
void* rev(struct node *prev,struct node *cur){
if(cur!=NULL){
printf("Works");
rev(cur,cur->next);
cur->next=prev;
}
else{
start=prev;
}
}
And the related code in main is:
main(){
struct node *temp;
temp=start;
/*Code to insert values*/
rev(NULL,temp);
}
Now the code takes input and prints it perfectly, but after I call rev() function the same traversal function prints nothing.
I did run the code on debugger line by line n it gave me the following output:
rev (prev=0x0, cur=0x0)
Also since cur is somehow NULL, the if part of rev() never gets executed and only the else executes once.
When I take input in my create() function I do update start to the first element of the linked list and even in main a print statement proves it is so.
But then why the function rev() always receives input parameters as NULL?
Please comment if any extra information is required.
Specific problems with your code: your main() function lacks sufficient code to test the reversal functionality (e.g. it doesn't create any nodes!); your create() routine really needs a head and tail pointer to work correctly, not the current head and start; your reversal function maintaines the head/start pointer but doesn't handle a tail pointer; you've redundant code in your if and else clauses that can be pulled out of the conditional; you declared rev() a void * instead of simply a void.
I've reworked your code below with addressing the above changes along with some style issues:
#include <stdlib.h>
#include <stdio.h>
struct node {
int value;
struct node *next;
};
// Global pointers to structure
struct node *head = NULL, *tail = NULL;
// Function to add node
void create(int data) {
struct node *temporary = malloc(sizeof(struct node));
temporary->value = data;
temporary->next = NULL;
if (head == NULL) {
head = temporary;
} else {
tail->next = temporary;
}
tail = temporary;
}
// Function to reverse the linked list
void reverse(struct node *previous, struct node *current) {
if (current != NULL) {
reverse(current, current->next);
current->next = previous;
} else {
head = previous;
}
if (previous != NULL) {
tail = previous;
}
}
void display(struct node *temporary) {
while (temporary != NULL) {
printf("%d ", temporary->value);
temporary = temporary->next;
}
printf("\n");
}
// And the related code in main is:
int main() {
/* Code to insert values */
for (int i = 1; i <= 10; i++) {
create(i);
}
display(head);
reverse(NULL, head);
display(head);
create(0);
display(head);
return 0;
}
OUTPUT
> ./a.out
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1 0
>
You should add a routine to free the nodes in the linked list.
This is an interview Question.
A binary search tree is given and the values of two nodes have been swapped. The question is how to find both the nodes and the swapped values in a single traversal of the tree?
i have tried to solve this using below code but i am not able to stop the recursion so i am getting segmentation fault. help me how to stop recursion.
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <stdlib.h>
/* A binary tree node has data, pointer to left child
and a pointer to right child */
struct node
{
int data;
struct node* left;
struct node* right;
};
/* Helper function that allocates a new node with the
given data and NULL left and right pointers. */
struct node* newNode(int data)
{
struct node* node = (struct node*)
malloc(sizeof(struct node));
node->data = data;
node->left = NULL;
node->right = NULL;
return(node);
}
void modifiedInorder(struct node *root, struct node **nextNode)
{
static int nextdata=INT_MAX;
if(root)
{
modifiedInorder(root->right, nextNode);
if(root->data > nextdata)
return;
*nextNode = root;
nextdata = root->data;
modifiedInorder(root->left, nextNode);
}
}
void inorder(struct node *root, struct node *copyroot, struct node **prevNode)
{
static int prevdata = INT_MIN;
if(root)
{
inorder(root->left, copyroot, prevNode);
if(root->data < prevdata)
{
struct node *nextNode = NULL;
modifiedInorder(copyroot, &nextNode);
int data = nextNode->data;
nextNode->data = (*prevNode)->data;
(*prevNode)->data = data;
return;
}
*prevNode = root;
prevdata = root->data;
inorder(root->right, copyroot, prevNode);
}
}
/* Given a binary tree, print its nodes in inorder*/
void printInorder(struct node* node)
{
if (node == NULL)
return;
/* first recur on left child */
printInorder(node->left);
/* then print the data of node */
printf("%d ", node->data);
/* now recur on right child */
printInorder(node->right);
}
int main()
{
/* 4
/ \
2 3
/ \
1 5
*/
struct node *root = newNode(1); // newNode will return a node.
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
printf("Inorder Traversal of the original tree\n ");
printInorder(root);
struct node *prevNode=NULL;
inorder(root, root, &prevNode);
printf("\nInorder Traversal of the fixed tree \n");
printInorder(root);
return 0;
}
Walk to the tree using inorder traversal. By using that you will get all the elements sorted and the one element that will be greater than the surrounding elements is swapped.
For example consider this below binary tree
_ 20 _
/ \
15 30
/ \ / \
10 17 25 33
/ | / \ / \ | \
9 16 12 18 22 26 31 34
First, we linearize this into an array and we get
9 10 16 15 12 17 18 20 22 25 26 30 31 33 34
Now you can notice that 16 is greater than its surrounding elements and that 12 is less than them. This immediately tells us that 12 and 16 were swapped.
The following function validates if a tree is BST or not by recursively iterating both left and right subtrees while tightening the bounds.
I believe it can be modified to achieve the above task by
Instead of returning false, return temp i.e. pointer to node which fails the tree from being BST.
There would be two such instances which gives both the swapped values.
EDIT: We would need to distinguish between recursive function returning true vs pointer to node which is swapped
This assumes that there are only two such values as mentioned in the problem definition
bool validate_bst(tnode *temp, int min, int max)
{
if(temp == NULL)
return true;
if(temp->data > min && temp->data < max)
{
if( validate_bst(temp->left, min, temp->data) &&
validate_bst(temp->right, temp->data, max) )
return true;
}
return false;
}
The main would call above api like this
validate_bst(root, -1, 100); // Basically we pass -1 as min and 100 as max in
// this instance
We can solve this in O(n) time and with a single traversal of the given BST. Since inorder traversal of BST is always a sorted array, the problem can be reduced to a problem where two elements of a sorted array are swapped. There are two cases that we need to handle:
6
/ \
10 2
/ \ / \
1 3 7 12
1. The swapped nodes are not adjacent in the inorder traversal of the BST.
For example, Nodes 10 and 2 are swapped in {1 10 3 6 7 2 12}.
The inorder traversal of the given tree is 1 10 3 6 7 2 12
If we observe carefully, during inorder traversal, we find node 3 is smaller than the previous visited node 10. Here save the context of node 10 (previous node). Again, we find that node 2 is smaller than the previous node 7. This time, we save the context of node 2 ( current node ). Finally swap the two node’s values.
2. The swapped nodes are adjacent in the inorder traversal of BST.
6
/ \
10 8
/ \ / \
1 3 7 12
For example, Nodes 10 and 2 are swapped in {1 10 3 6 7 8 12}.
The inorder traversal of the given tree is 1 10 3 6 7 8 12
Unlike case #1, here only one point exists where a node value is smaller than previous node value. e.g. node 10 is smaller than node 36.
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
void recoverTreeUtil(TreeNode *root, TreeNode **first, TreeNode **middle, TreeNode **last, TreeNode **prev) {
if (root) {
recoverTreeUtil(root->left, first, middle, last, prev);
if (*prev && (*prev)->val > root->val) {
if (!(*first)) {
*first = *prev;
*middle = root;
} else *last = root;
}
*prev = root;
recoverTreeUtil(root->right, first, middle, last, prev);
}
}
void recoverTree(TreeNode* root) {
TreeNode *first, *middle, *last, *prev;
first = middle = last = prev = nullptr;
recoverTreeUtil(root, &first, &middle, &last, &prev);
if (first && last) swap(first->val, last->val);
else if (first && middle) swap(first->val, middle->val);
}
};
I found another solution to this questions on Geeksforgeeks.com ..............guys u can look into this thread for more explanation of below code http://www.geeksforgeeks.org/archives/23616
// Two nodes in the BST's swapped, correct the BST.
#include <stdio.h>
#include <stdlib.h>
/* A binary tree node has data, pointer to left child
and a pointer to right child */
struct node
{
int data;
struct node *left, *right;
};
// A utility function to swap two integers
void swap( int* a, int* b )
{
int t = *a;
*a = *b;
*b = t;
}
/* Helper function that allocates a new node with the
given data and NULL left and right pointers. */
struct node* newNode(int data)
{
struct node* node = (struct node *)malloc(sizeof(struct node));
node->data = data;
node->left = NULL;
node->right = NULL;
return(node);
}
// This function does inorder traversal to find out the two swapped nodes.
// It sets three pointers, first, middle and last. If the swapped nodes are
// adjacent to each other, then first and middle contain the resultant nodes
// Else, first and last contain the resultant nodes
void correctBSTUtil( struct node* root, struct node** first,
struct node** middle, struct node** last,
struct node** prev )
{
if( root )
{
// Recur for the left subtree
correctBSTUtil( root->left, first, middle, last, prev );
// If this node is smaller than the previous node, it's violating
// the BST rule.
if (*prev && root->data < (*prev)->data)
{
// If this is first violation, mark these two nodes as
// 'first' and 'middle'
if ( !*first )
{
*first = *prev;
*middle = root;
}
// If this is second violation, mark this node as last
else
*last = root;
}
// Mark this node as previous
*prev = root;
// Recur for the right subtree
correctBSTUtil( root->right, first, middle, last, prev );
}
}
// A function to fix a given BST where two nodes are swapped. This
// function uses correctBSTUtil() to find out two nodes and swaps the
// nodes to fix the BST
void correctBST( struct node* root )
{
// Initialize pointers needed for correctBSTUtil()
struct node *first, *middle, *last, *prev;
first = middle = last = prev = NULL;
// Set the poiters to find out two nodes
correctBSTUtil( root, &first, &middle, &last, &prev );
// Fix (or correct) the tree
if( first && last )
swap( &(first->data), &(last->data) );
else if( first && middle ) // Adjacent nodes swapped
swap( &(first->data), &(middle->data) );
// else nodes have not been swapped, passed tree is really BST.
}
/* A utility function to print Inoder traversal */
void printInorder(struct node* node)
{
if (node == NULL)
return;
printInorder(node->left);
printf("%d ", node->data);
printInorder(node->right);
}
/* Driver program to test above functions*/
int main()
{
/* 6
/ \
10 2
/ \ / \
1 3 7 12
10 and 2 are swapped
*/
struct node *root = newNode(6);
root->left = newNode(10);
root->right = newNode(2);
root->left->left = newNode(1);
root->left->right = newNode(3);
root->right->right = newNode(12);
root->right->left = newNode(7);
printf("Inorder Traversal of the original tree \n");
printInorder(root);
correctBST(root);
printf("\nInorder Traversal of the fixed tree \n");
printInorder(root);
return 0;
}
Output:
Inorder Traversal of the original tree
1 10 3 6 7 2 12
Inorder Traversal of the fixed tree
1 2 3 6 7 10 12
Time Complexity: O(n)
For more test cases please refer to this link http://ideone.com/uNlPx
My C++ Solution:
struct node *correctBST( struct node* root )
{
//add code here.
if(!root)return root;
struct node* r = root;
stack<struct node*>st;
// cout<<"1"<<endl;
struct node* first = NULL;
struct node* middle = NULL;
struct node* last = NULL;
struct node* prev = NULL;
while(root || !st.empty()){
while(root){
st.push(root);
root = root->left;
}
root = st.top();
st.pop();
if(prev && prev->data > root->data){
if(!first){
first = prev;
middle = root;
}
else{
last = root;
}
}
prev = root;
root = root->right;
}
if(first && last){
swap(first->data,last->data);
}
else{
swap(first->data,middle->data);
}
return r;
}