Understanding code in c (linked lists) - c

I am having big problems understanding linked lists and I would be very thankful if someone could explain me the following.
Element_t *pushfront(Element_t *list)
{
if(list==0)
return allocate();
list->prev=allocate();
list->prev->next=list;
list=list->prev;
return list;
}
What here means list->prev->next=list ?
What means this: f->next->prev=f->prev?
I know that this is just a part from program code, but I hope someone can give me general meaning of these as simpliest as can?

The list has nodes that have references to the previous node and to the next node in the list.
The function gets the first node of the list. So this first node does not have a previous node.
In this statement
list->prev=allocate();
a previous node is created because as it follows from the function name it push a new node at the beginning of the list.
In this statement
list->prev->next=list;
expression list->prev yields the address of the new created node. This created node shall point to the current first node of the list. Thus its data member next shall contain the address of the node list.
And this statement
list->prev->next=list;
does this.
It can be imagined simpler if to introduce an intermediate variable.
For example
Element_t *new_node = allocate();
list->prev = new_node; // list->prev=allocate();
new_node->next = list; //list->prev->next=list;
list = new_node; //list=list->prev;
return list;
As for this question
What means this: f->next->prev=f->prev?
then it looks like that the node f is removed from the list. Now its next node (f->next) will not point to f but will point to the preceding node of f.
Again it will be more clear if to introduce intermediate variables.
Element_t *previous_node_of_f = f->prev;
Element_t *next_node_of_f = f->next;
next_node_of_f->prev = previous_node_of_f; // f->next->prev=f->prev
If to add also a statement like this
previous_node_of_f->next = next_node_of_f;
then the node f will be fully removed from the list.
--------------------------------------------------------
| prev ^
| |
---------------------- ---------------------- ----------------------
| previous_node_of_f | | f | | next_node_of_f |
---------------------- ---------------------- ----------------------
| ^
| next |
-------------------------------------------------------

Here is your code with comments, which tell you what is happening.
Element_t *pushfront(Element_t *list)
{
if(list==0) // If the list is emtpy
return allocate(); /* then you simply create a new node, which
represents your list and return it. The size of your list grew from 0 to 1.*/
list->prev=allocate(); /*If the list is not empty, you add a new node by creating it,
and then the prev pointer of the first element in the list (list->prev)
is set to this new element, as you want it to be first.*/
list->prev->next=list; /*Then you need to set the next pointer
to the element you just added. The new element is at list->prev,
so by list->prev->next, you just say, that the next element of the one
you just created is the element that was first before you added the new one*/
list=list->prev; /* Here you just set the new element as the head of the list*/
return list; /*And here you return the new list*/
}
Note, that your list is always passed just as a pointer to the first element, as that's all you need. You can then access all of the elements by next pointer, which is set for each element in the list.

Firstly the linked lists are linked each others with pointers. They are not in order in fact they are distributed on memory.
Let me get on your question-1 list->prev->next=list;
Here you are linking the previous node with the current node. This code means that link the next of previous to the current node. Then the previous node now linked with next pointer which is defined in structure.
Get the question-2 f->next->prev=f->prev;
I dont know where this is defined but here you are doing that a circled linked list. The last node linked to the first node by this code.

Element_t is a probably a typedef similar to the following:
typedef struct Element {
struct Element * next;
struct Element * prev;
void * data;
} Element_t;
Assuming this, your linked list basicly works like this:
(list)
A B C
+----------+ +----------+ +----------+
| next=B |--->| next=C |--->| next=0 |
| prev=0 |<---| prev=A |<---| prev=B |
| data="A" | | data="B" | | data="C" |
+----------+ +----------+ +----------+
So now you want to add a new node N in front of A
(list)
N A B C
+----------+ +----------+ +----------+ +----------+
| next=A |--->| next=B |--->| next=C |--->| next=0 |
| prev=0 |<---| prev=N |<---| prev=A |<---| prev=B |
| data="N" | | data="A" | | data="B" | | data="C" |
+----------+ +----------+ +----------+ +----------+
so, 1. A->prev needs to be set to N and 2. N->next needs to set to A.
list->prev=allocate(); this allocates the new N and already assigns A->prev=N.
Next in line: list->prev->next=list: Read list->prev as the new node that just got alloced. Then it's N->next=A - the second step.
And your new element is linked in the list. Obviously, allocate() needs to initialize next and prev to NULL.
What means this: f->next->prev=f->prev?
Depends on where it's written. Here, it's probably part of a function, that removes a node from the list.

Related

Pointers in Structure pointing to another strucutre

I am trying to understand how pointers in linked lists work. So far i am having lots of trouble trying to figure out where the pointer is pointing to and how a pointer of a type struct works( I know we need to allocate memory from the heap but can't quite understand it, but maybe that's a different question altogether).
Lets take this structure:
typedef struct Node {
int data;
struct Node *link;
} Node;
What I think will happen now is:
Say you have a pointer of type Node in the main function, Node* p and this is allocated memory (using malloc).
Now if we have some data p->data=5; , p points to the beginning of this data (at least this is what i think is happening).
Where exactly does link point to?
So now, i come across this particular piece of code:
typedef struct Node {
int data;
struct Node *link;
} Node;
typedef struct List {
Node* head;
int number_of_nodes;
} List;
So this is complete chaos in my brain! .
Now in the structure List, what is head doing? What is it pointing to? And how would you create a linked list at all with these two lists??
I am really trying my level best to understand how linked lists work, but all the pointers make it too hard to keep track of. You might suggest i start with something simple and i did, and i have already mentioned how much i understand. But the head pointer in the second structure has completely thrown me off track!
It would make my life so much more easier if someone could help me explain it while keeping track of the pointers.
Where exactly does link point to?
link points to another object of the same type:
+------+------+ +------+------+ +------+------+
| data | link |---->| data | link |---->| data | link | ----> ...
+------+------+ +------+------+ +------+------+
Now in the structure List, what is head doing? What is it pointing to?
head points to the first node in a list:
+-----------------+ +------+------+ +------+------+
| head |---->| data | link |---->| data | link |----> ...
+-----------------+ +------+------+ +------+------+
| number_of_nodes |
+-----------------+
I am really trying my level best to understand how linked lists work,
Don't feel bad - linked lists threw me for a loop in my Data Structures class (my first "hard" CS class). It took me a solid week longer than my classmates to grok the concept. Hopefully the pictures help.
Edit
what happens if you have a pointer to the structure List, memory allocated and all? Where does it point to then (according to the diagrams, which did help by the way)
So, let's assume you have the following code:
/**
* Create a new list object. head is initially NULL,
* number_of_nodes initially 0.
*/
List *newList( void )
{
List *l = malloc( sizeof *l );
if ( l )
{
l->head = NULL;
l->number_of_nodes = 0;
}
return l;
}
int main( void )
{
List *l = newList();
...
}
Then your picture looks like this:
+---------+ +--------------------+
| l: addr | ----> | head: NULL |
+---------+ +--------------------+
| number_of_nodes: 0 |
+--------------------+
(addr represents some arbitrary memory address)
Now let's say you add a node to your list:
/**
* Create a new node object, using the input data
* link is initially NULL
*/
Node *newNode( int data )
{
Node *n = malloc( sizeof *n );
if ( n )
{
n->data = data;
n->link = NULL;
}
return n;
}
void insertNode( List *l, int data )
{
Node *n = newNode( data );
if ( n )
{
/**
* If list is initially empty, make this new node the head
* of the list. Otherwise, add the new node to the end of the
* list.
*/
if ( !l->head ) // or n->head == NULL
{
l->head = n;
}
else
{
/**
* cur initially points to the first element in the list.
* While the current element has a non-NULL link, follow
* that link.
*/
for ( Node *cur = l->head; cur->link != NULL; cur = cur->link )
; // empty loop body
cur->link = n;
}
l->number_of_nodes++;
}
}
int main( void )
{
List *l = newList();
insertNode( l, 5 );
...
}
Now your picture looks like this:
+---------+ +--------------------+ +------------+
| l: addr | ----> | head: addr | ---> | data: 5 |
+---------+ +--------------------+ +------------+
| number_of_nodes: 1 | | link: NULL |
+--------------------+ +------------+
You could add another node:
int main( void )
{
List *l = newList();
insertNode( l, 5 );
insertNode( l, 3 );
...
}
then your picture becomes
+---------+ +--------------------+ +------------+ +------------+
| l: addr | ----> | head: addr | ---> | data: 5 | +--> | data: 3 |
+---------+ +--------------------+ +------------+ | +------------+
| number_of_nodes: 2 | | link: addr | --+ | link: NULL |
+--------------------+ +------------+ +------------+
Naturally, you'd want to add some error checking and messages in case a node couldn't be allocated (it happens). And you'd probably want an ordered list, where elements are inserted in order (ascending, descending, whatever). But this should give you a flavor of how to build lists.
You'd also need functions to remove items and free that memory. Here's how I'd free an entire list:
void freeList( List *l )
{
Node *prev, *cur = l->head;
while( cur && cur->link )
{
prev = cur;
cur = cur->link;
free( prev );
}
free( cur );
}
int main( void )
{
List *l = newList();
...
freeList( l );
free( l );
...
}
… a pointer of a type struct…
A pointer cannot be of a type struct. A pointer can point to a structure.
C has objects. Objects include char, int, double, structures, and other things. A structure is a collection of objects grouped together.
In main, if you define p with Node *p;, you then have a pointer p. It has no value because you have not given it a value. When you execute p = malloc(sizeof *p);, you request enough memory for the size of the thing p points to (*p). If malloc returns a non-null pointer, then p points to a Node structure.
Then p->data refers to the data member of that structure. p->data is shorthand for (*p).data, in which *p means “the object p points to” and .data means “the data member in that object.”
After p = malloc(sizeof *p); and p->data = 5;, p->link does not point to anything because you have not assigned it a value. In a linked list, you would use malloc to get memory for another Node, and then you would set the p->link in one Node to point to the new Node. In each Node, its link member points to the next Node in the list. Except, in the last Node, p->link is set to a null pointer to indicate it is the last Node.
In List, you would set head to point to the first Node in a list of Node objects.

Having trouble understanding the definition of a linked list

I have some questions regarding the definition of a linked list as it was defined in my class.
This is what was used:
typedef struct node_t {
int x;
struct node_t *next;
} *Node;
Now, I understand that this way we created a shorter way to use pointers to the struct node_t. Node will be used as struct node_t*.
Now, say we want to create a linked list. For example:
Node node1 = malloc(sizeof(*node1));
Node node2 = malloc(sizeof(*node2));
Node node3 = malloc(sizeof(*node3));
node1->x = 1;
node1->next = node2;
node2->x = 4;
node2->next = node3;
node3->x = 9;
node3->next = NULL;
This is roughly how I imagine this (The circles represent the structures):
Now I know it's wrong, but I can't understand why. We have a pointer, node1, that points to our structure. Then, we point at node2, which points at another structure and so and so on.
Another things is, I can't understand how is it possible to have the longer arrows in the picture. Shouldn't we only be able to point to a structure from each lower part of the circle, and not to a pointer to a structure? How is this possible?
If anyone here could make things a little clearer it would be hugely appreciated. Thank a lot.
You have three linked nodes, and additional local pointers pointing to them.
The nodes don't know anything about those local pointers though, even if it is often convenient to use their names to refer to the nodes.
Instead, they know the next node in the sequence, respectively the last node knows none.
Put another way, your image is flat-out wrong.
+---+------+
node1 --> | 1 | next |
+---+-|----+
|
v
+---+------+
node2 --> | 4 | next |
+---+-|----+
|
v
+---+------+
node3 --> | 9 | NULL |
+---+------+
Assignment is a transitive operation. So,
node1->next = node2;
would mean that node1->next points to whatever node2 was pointing to. And, in particular, node1->next does not point to node2 itself.
Each of node1, node2, and node3 name a variable that is a pointer.
node1 node2 node3
+---+ +---+ +---+
| * | | * | | * |
+ | + + | + + | +
v v v
+---+---+ +---+---+ +---+---+
| 1 | * --> | 4 | * --> | 9 | * --> NULL
+---+---+ +---+---+ +---+---+
typedef struct node_t {
int x;
struct node_t *next;
} *Node; /* <-- don't typedef pointers */
Simply use Node instead of Node * and then allocate with:
Node *node1 = malloc(sizeof(*node1));
Why? Somebody looking at your code 100 lines below the declaration of your typedef will not inherently know whether Node is a type, or whether it is a pointer-to-type. This type of confusion will only grow as your code grows in size. Review: Is it a good idea to typedef pointers?.
(note: good job using the dereferenced pointer to set the typesize in sizeof)
A Linked List
A linked list is simply a clever data structure that allows you to iterate over a number of independently allocated nodes. Each node contains some data and then a pointer to the next node in the list, or NULL if that node is the final node in the list.
(for a doubly-linked list, you simply add a prev pointer that also points to the node before the current node in the list. You also have circular lists where the last node points back to the first allowing iteration from any node to any other node in the list regardless of which node you begin iterating with. For a doubly-linked circular list, you can iterate the entire list in both directions from any node)
In your case, your list is simply:
node1 +-> node2 +-> node3
+------+ | +------+ | +------+
| data | | | data | | | data |
|------| | |------| | |------|
| next |--+ | next |--+ | next |---> NULL
+------+ +------+ +------+
Where your data is a single integer value and your next pointer simply holds the address of the next node in your list, or NULL if it is the final node in the list. Adding your data, your list would be:
node1 +-> node2 +-> node3
+------+ | +------+ | +------+
| 1 | | | 4 | | | 9 |
|------| | |------| | |------|
| next |--+ | next |--+ | next |---> NULL
+------+ +------+ +------+
When creating a list, the first node is usually referred to as the head of the list and the last node the tail of the list. You must always preserve a pointer to the head of your list as that pointer holds the beginning list-address. For efficient insertions into the list, it is also a good idea to keep a pointer to the tail node so you can simply insert the new node without iterating over the list to find the last node each time, e.g.:
Node *newnode = malloc(sizeof(*newnode)); /* allocate */
newnode->next = NULL; /* initialize next NULL */
tail->next = newnode; /* assign to tail */
tail = newnode; /* set new tail at newnode */
Lists are fundamental to C, there are many used in the Linux kernel itself. Take the time to understand them and how to write them in the differing variants. You'll be glad you did. Lastly, don't forget to write a simple function to free your list when you are done (and free the data as well if it is allocated). A simple free_list function would be:
void free_list (Node *list)
{
while (list) {
Node *victim = list; /* separate pointer to node to free */
list = list->next; /* can you see why you iterate next... */
free (victim); /* before you free the victim node? */
}
}
Let me know if you have further questions.

Hassle in Linkedlist in C

Suppose I have 3 nodes already in the list (i.e. 10 , 20). And I want to insert 30. So wrote as below
struct node *p,*temp;
p=start;
temp=(struct node*)malloc(sizeof(struct node));
temp->info=30;
temp->link=NULL;
while(p-link!=NULL)
{
p=p->link;
}
p->link=temp;
It worked perfectly until I do this: while(p!=NULL) rest is same..
Similarly in case of showing the node I wrote as follows
while(p!=NULL)
{
printf("%d \n",p->info);
p=p->link;
}
This also worked fine until I changed it to: while(p->link!=NULL)
I want to know what is happening why is not working? Give me the reason why we are using while(p!=NULL) in case of showing the all the data and while(p->link!=NULL) in case of inserting any node?
Before the first while loop, you've got something like this. Two nodes (not three as you state) in a linked-list, pointed to by start and a new node, pointed to by temp:
start-->+---------+ +-->+---------+ +---------+<--temp
|info:10 | | |info:20 | |info:30 |
|link:xxxx|--+ |link:NULL| |link:NULL|
+---------+ +---------+ +---------+
To add the new node to the end of the list, you need to advance p from the first node (pointed to by start) until p points at the node whose link is NULL (i.e., until p->link!=NULL fails to be true):
start-->+---------+ +-->+---------+ +---------+<--temp
|info:10 | | |info:20 | |info:30 |
|link:xxxx|--+ |link:NULL| |link:NULL|
+---------+ +---------+ +---------+
^
|
p -+
Once you have found the last node, you then "plumb" in your new node to get a three-element list:
start-->+---------+ +-->+---------+ +-->+---------+
|info:10 | | |info:20 | | |info:30 |
|link:xxxx|--+ |link:yyyy|--+ |link:NULL|
+---------+ +---------+ +---------+
However, when you're printing all of the nodes, you start p at the first node (i.e. start) and print the details of every node until p has been set to NULL (i.e. p!=NULL fails to be true). If you stopped when p->link was NULL, you would not have printed the last node.
A linked list, in C is a struct that contains data and a pointer to the next element (and maybe a pointer to the previous element, but that doesn't seem to be your case). It would be something like this:
struct node {
int data; //could be any type
struct node *next;
};
To insert elements in the end of the list, you need to go to the end of it - when there is no next element. To do that, you check node->next == NULL. Then you make node->next = new_node
To find an element in the list, you need to loop for all elements until you find it. If the element doesn't exists in the list, you need to prevent the user from accessing an invalid element, so you test node == NULL to finish the loop safely. This case is also applicable if you want to just print all data in the list - you need to reach all elements, the test would be the same (if you were testing node->next == NULL, you would skip the last element).

View item of linked list

I want to view all the items of a linked list.
I've created a three items list, and when i use the below "show_items" function, it just show the first element, and the other items can't be showed becuase a segmentation fault error is given by compiler.
#include <stdio.h>
#include <stdlib.h>
struct list{
int age;
struct list *next;
};
void create_item(int *total_items, struct list *where_is_first_item, struct list *where_is_last_item)
{
struct list *generic_item;
generic_item = malloc(sizeof(struct list));
printf("\nage of item %d: ", (*total_items)+1);
scanf("%d", &generic_item->age);
if(*total_items == 0){
where_is_first_item->next=generic_item;
where_is_last_item->next=generic_item;
printf("\nitem created\n");
}
else{
where_is_last_item->next=generic_item;
printf("\nitem created\n");
}
void show_items(int *total_items, struct list *where_is_first_item, struct list *temp){
temp=where_is_first_item->next;
int i;
for(i=0;i<*total_items;i++){
printf("age of element %d: %d\n", i+1, temp->age);
temp=temp->next;
}
}
int main (void){
int total_items=0;
struct list *where_is_first_item;
where_is_first_item=malloc(sizeof(struct list));
struct list *temp;
temp=malloc(sizeof(struct list));
printf("\n\n\tCREATE A NEW ITEM\n");
create_item(&total_items, where_is_first_item, where_is_last_item);
total_items++;
show_items(&total_items, where_is_first_item, temp);
return 0;
}
Well, I see two major issues in the code that you're showing us:
I don't see three members being created like you claim in the problem statement.
The memory returned by malloc() has unspecified contents, and you're expecting it to have useful contents.
And then for just odd things:
Why do you pass total_items as a pointer if you never modify it.
Why do you pass temp as an argument if you promptly ignore the value you passed in?
When iterating through your list, you should be checking the value of temp to make sure it isn't NULL before trying to access it. At the least, you should use the following:
for ( i = 0; i < *total_items && temp != NULL; i++ )
...
although it's more common to iterate through a list like
while ( temp != NULL ) // or just while ( temp )
{
...
temp = temp->next;
}
Your usage of temp seems confused; does it serve any purpose in main after you've called show_items? If not, you should make it local to show_items and not pass it as an argument:
void show_items(int *total_items, struct list *where_is_first_item)
{
struct list *temp = where_is_first_item->next;
...
}
In the code you've posted, total_items is initialized to 0; as written, this code shouldn't attempt to output anything. It would make life easier for everyone if you would either post the actual code you're having problems with, or if it's too big, reduce it to a representative sample of the problem.
Edit
Duh. Now I see the problem. You're never properly setting the next item in your generic_item struct.
So you have two pointers to keep track of the head and tail of your list, where_is_first_item and where_is_last_item. When you add the first item to the list, you create generic_item and set your head and tail pointers to point to it through their respective next members, giving you something like this (using head and tail instead of where_is_first_item and where_is_last_item for brevity):
head generic_item tail
+--+--+ +--+--+ +--+--+
| | -+------->| | -+-??? | | -+---+
+--+--+ +--+--+ +--+--+ |
^ |
| |
+------------------------+
So far so good. However, when you add a second item, you only update the list tail pointer; you don't create an explicit link from the first item to the second, so you wind up with something like the following:
head generic_item tail
+--+--+ +--+--+ +--+--+ +--+--+
| | -+------->| | -+-??? | | -+-??? | | -+--+
+--+--+ +--+--+ +--+--+ +--+--+ |
^ |
| |
+------------------------+
Hopefully you can see the problem. The next pointer in the first list element is never initialized, so it contains an indeterminate value that doesn't correspond to a valid address.
You need an extra step when you append a new element to the list:
struct list *pre = where_is_last_item->next;
pre->next = generic_item;
where_is_last_item->next = generic_item;
That will give you something like the following:
head pre generic_item tail
+--+--+ +--+--+ +--+--+ +--+--+
| | -+------->| | -+------->| | -+-??? | | -+--+
+--+--+ +--+--+ +--+--+ +--+--+ |
^ |
| |
+------------------------+
As a rule, you should always initialize the next member to NULL, rather than leave it indeterminate. It's easy to test against NULL; it's much harder to determine the validity of a non-NULL pointer value.

How to remove a node any integer data

I am working on my homework but I really don't know how to remove a node with an integer data I already have a code for adding of nodes, I just need to remove nodes, or can you give me atleast an algorithm of it goes like this
addnode(root,5);
addnode(root,2);
addnode(root,6);
display(root);
removenode(root,5);
display(root);
removenode(root,6);
do you guys need code for my addition code? but our proff already gave us the code for showing the display of nodes ;
void display(struct node *head)
{
struct node *traverser;
traverser = head;
while(traverser!=NULL)
{
printf("%d\n",traverser->x);
traverser=traverser->next;
}
}
struct node
{
int data;
struct node *next
};
a question though what does traverser=traverser->next;
I assume you are dealing with a linked list. These are usually built up of entries that contain data and a link to the following name (thus the name):
struct node {
int data;
struct node *next;
}
As you can see, the link is a pointer in C. Which should point to the next entry. To start traversing a list, you usually have got a head.
If you want to remove an entry, you need to traverse the list and once you found the entry you want to remove, simply rearrange the pointers:
void removeEntry(int data, struct node *head) {
struct node *prev = NULL, *current = head;
while(current->data != data) {
prev = current; // current will always point to the entry in front of current
current = current->next;
if(current == NULL) // end of list and no match
return;
}
// now current is pointing to the entry you want to remove
// remove it just by rearrangeing pointers
prev->next = current->next;
free(current); // I assume you malloc'ed the memory
}
Note: Please note that I omitted errorchecking here. Also, sometimes the head is a fixed item in which no data is stored (would work in my case), sometimes head can contain data itself (in this case you need to check if the element you want to remove is the first element and relink head accordingly)
1)
you can delete the node from the linked list like(considering head is not dummy node i.e head also contains data)...
int flag=0;
if(head->data==data_todel) head=head->next; //if head contains the data
ptr=head;
while(ptr->next!=NULL && flag==0)
{
if(ptr->next->data!=data_todel)
ptr=ptr->next;
else
{
flag=1;
break;
}
}
if(flag) ptr->next=ptr->next->next;
you need to use two pointers to free the deleted node.
2)
+------+-------+ +------+-------+
| data1| next | | data2| next |
+------+-------+ +------+-------+
^ | ^
| | |
| +--------------+
+---------+
|traverser|
+---------+
after traverser=traverser->next
+------+-------+ +------+-------+
| data1| next | | data2| next |
+------+-------+ +------+-------+
| ^ ^
| | |
+--------------+ |
|
+---------+
|traverser|
+---------+
that means it is assigning the address of of the next node currently pointed by traverser.
a question though what does traverser=traverser->next;
It sets the pointer to the next element in the queue. Iterating in your while cicle until it reaches a null pointer (end of the queue).
(You didn't post the node structure declaration, so i'm just guessing)
The next field is the key in the linked list. Each element has a successor, that way the list is linked. So, when you traverse the list, you start at the first element head and move from one element to the next until there is no next element.
To remove an entry, you need to cycle through the list until you find that entry. Then, set the next variable of the previous entry to the next entry. That way, the element is removed from the list.

Resources